if_nfe.c revision 159952
1159952Sobrien/*	$OpenBSD: if_nfe.c,v 1.57 2006/04/26 02:07:29 jsg Exp $	*/
2159952Sobrien
3159952Sobrien/*-
4159952Sobrien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr>
5159952Sobrien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org>
6159952Sobrien *
7159952Sobrien * Permission to use, copy, modify, and distribute this software for any
8159952Sobrien * purpose with or without fee is hereby granted, provided that the above
9159952Sobrien * copyright notice and this permission notice appear in all copies.
10159952Sobrien *
11159952Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12159952Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13159952Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14159952Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15159952Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16159952Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17159952Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18159952Sobrien */
19159952Sobrien
20159952Sobrien/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */
21159952Sobrien
22159952Sobrien#include "bpfilter.h"
23159952Sobrien#include "vlan.h"
24159952Sobrien
25159952Sobrien#include <sys/param.h>
26159952Sobrien#include <sys/endian.h>
27159952Sobrien#include <sys/systm.h>
28159952Sobrien#include <sys/types.h>
29159952Sobrien#include <sys/sockio.h>
30159952Sobrien#include <sys/mbuf.h>
31159952Sobrien#include <sys/queue.h>
32159952Sobrien#include <sys/malloc.h>
33159952Sobrien#include <sys/kernel.h>
34159952Sobrien#include <sys/device.h>
35159952Sobrien#include <sys/socket.h>
36159952Sobrien
37159952Sobrien#include <machine/bus.h>
38159952Sobrien
39159952Sobrien#include <net/if.h>
40159952Sobrien#include <net/if_dl.h>
41159952Sobrien#include <net/if_media.h>
42159952Sobrien
43159952Sobrien#ifdef INET
44159952Sobrien#include <netinet/in.h>
45159952Sobrien#include <netinet/in_systm.h>
46159952Sobrien#include <netinet/in_var.h>
47159952Sobrien#include <netinet/ip.h>
48159952Sobrien#include <netinet/if_ether.h>
49159952Sobrien#endif
50159952Sobrien
51159952Sobrien#if NVLAN > 0
52159952Sobrien#include <net/if_types.h>
53159952Sobrien#include <net/if_vlan_var.h>
54159952Sobrien#endif
55159952Sobrien
56159952Sobrien#if NBPFILTER > 0
57159952Sobrien#include <net/bpf.h>
58159952Sobrien#endif
59159952Sobrien
60159952Sobrien#include <dev/mii/mii.h>
61159952Sobrien#include <dev/mii/miivar.h>
62159952Sobrien
63159952Sobrien#include <dev/pci/pcireg.h>
64159952Sobrien#include <dev/pci/pcivar.h>
65159952Sobrien#include <dev/pci/pcidevs.h>
66159952Sobrien
67159952Sobrien#include <dev/pci/if_nfereg.h>
68159952Sobrien#include <dev/pci/if_nfevar.h>
69159952Sobrien
70159952Sobrienint	nfe_match(struct device *, void *, void *);
71159952Sobrienvoid	nfe_attach(struct device *, struct device *, void *);
72159952Sobrienvoid	nfe_power(int, void *);
73159952Sobrienvoid	nfe_miibus_statchg(struct device *);
74159952Sobrienint	nfe_miibus_readreg(struct device *, int, int);
75159952Sobrienvoid	nfe_miibus_writereg(struct device *, int, int, int);
76159952Sobrienint	nfe_intr(void *);
77159952Sobrienint	nfe_ioctl(struct ifnet *, u_long, caddr_t);
78159952Sobrienvoid	nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int);
79159952Sobrienvoid	nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int);
80159952Sobrienvoid	nfe_txdesc32_rsync(struct nfe_softc *, int, int, int);
81159952Sobrienvoid	nfe_txdesc64_rsync(struct nfe_softc *, int, int, int);
82159952Sobrienvoid	nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int);
83159952Sobrienvoid	nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int);
84159952Sobrienvoid	nfe_rxeof(struct nfe_softc *);
85159952Sobrienvoid	nfe_txeof(struct nfe_softc *);
86159952Sobrienint	nfe_encap(struct nfe_softc *, struct mbuf *);
87159952Sobrienvoid	nfe_start(struct ifnet *);
88159952Sobrienvoid	nfe_watchdog(struct ifnet *);
89159952Sobrienint	nfe_init(struct ifnet *);
90159952Sobrienvoid	nfe_stop(struct ifnet *, int);
91159952Sobrienstruct	nfe_jbuf *nfe_jalloc(struct nfe_softc *);
92159952Sobrienvoid	nfe_jfree(caddr_t, u_int, void *);
93159952Sobrienint	nfe_jpool_alloc(struct nfe_softc *);
94159952Sobrienvoid	nfe_jpool_free(struct nfe_softc *);
95159952Sobrienint	nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
96159952Sobrienvoid	nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
97159952Sobrienvoid	nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *);
98159952Sobrienint	nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
99159952Sobrienvoid	nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
100159952Sobrienvoid	nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *);
101159952Sobrienint	nfe_ifmedia_upd(struct ifnet *);
102159952Sobrienvoid	nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
103159952Sobrienvoid	nfe_setmulti(struct nfe_softc *);
104159952Sobrienvoid	nfe_get_macaddr(struct nfe_softc *, uint8_t *);
105159952Sobrienvoid	nfe_set_macaddr(struct nfe_softc *, const uint8_t *);
106159952Sobrienvoid	nfe_tick(void *);
107159952Sobrien
108159952Sobrienstruct cfattach nfe_ca = {
109159952Sobrien	sizeof (struct nfe_softc), nfe_match, nfe_attach
110159952Sobrien};
111159952Sobrien
112159952Sobrienstruct cfdriver nfe_cd = {
113159952Sobrien	NULL, "nfe", DV_IFNET
114159952Sobrien};
115159952Sobrien
116159952Sobrien/*#define NFE_NO_JUMBO*/
117159952Sobrien
118159952Sobrien#ifdef NFE_DEBUG
119159952Sobrienint nfedebug = 0;
120159952Sobrien#define DPRINTF(x)	do { if (nfedebug) printf x; } while (0)
121159952Sobrien#define DPRINTFN(n,x)	do { if (nfedebug >= (n)) printf x; } while (0)
122159952Sobrien#else
123159952Sobrien#define DPRINTF(x)
124159952Sobrien#define DPRINTFN(n,x)
125159952Sobrien#endif
126159952Sobrien
127159952Sobrienconst struct pci_matchid nfe_devices[] = {
128159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN },
129159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN },
130159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1 },
131159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN2 },
132159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN3 },
133159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4 },
134159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN5 },
135159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN1 },
136159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN2 },
137159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1 },
138159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2 },
139159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN1 },
140159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN2 },
141159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1 },
142159952Sobrien	{ PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2 }
143159952Sobrien};
144159952Sobrien
145159952Sobrienint
146159952Sobriennfe_match(struct device *dev, void *match, void *aux)
147159952Sobrien{
148159952Sobrien	return pci_matchbyid((struct pci_attach_args *)aux, nfe_devices,
149159952Sobrien	    sizeof (nfe_devices) / sizeof (nfe_devices[0]));
150159952Sobrien}
151159952Sobrien
152159952Sobrienvoid
153159952Sobriennfe_attach(struct device *parent, struct device *self, void *aux)
154159952Sobrien{
155159952Sobrien	struct nfe_softc *sc = (struct nfe_softc *)self;
156159952Sobrien	struct pci_attach_args *pa = aux;
157159952Sobrien	pci_chipset_tag_t pc = pa->pa_pc;
158159952Sobrien	pci_intr_handle_t ih;
159159952Sobrien	const char *intrstr;
160159952Sobrien	struct ifnet *ifp;
161159952Sobrien	bus_size_t memsize;
162159952Sobrien	pcireg_t memtype;
163159952Sobrien
164159952Sobrien	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, NFE_PCI_BA);
165159952Sobrien	switch (memtype) {
166159952Sobrien	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
167159952Sobrien	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
168159952Sobrien		if (pci_mapreg_map(pa, NFE_PCI_BA, memtype, 0, &sc->sc_memt,
169159952Sobrien		    &sc->sc_memh, NULL, &memsize, 0) == 0)
170159952Sobrien			break;
171159952Sobrien		/* FALLTHROUGH */
172159952Sobrien	default:
173159952Sobrien		printf(": could not map mem space\n");
174159952Sobrien		return;
175159952Sobrien	}
176159952Sobrien
177159952Sobrien	if (pci_intr_map(pa, &ih) != 0) {
178159952Sobrien		printf(": could not map interrupt\n");
179159952Sobrien		return;
180159952Sobrien	}
181159952Sobrien
182159952Sobrien	intrstr = pci_intr_string(pc, ih);
183159952Sobrien	sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, nfe_intr, sc,
184159952Sobrien	    sc->sc_dev.dv_xname);
185159952Sobrien	if (sc->sc_ih == NULL) {
186159952Sobrien		printf(": could not establish interrupt");
187159952Sobrien		if (intrstr != NULL)
188159952Sobrien			printf(" at %s", intrstr);
189159952Sobrien		printf("\n");
190159952Sobrien		return;
191159952Sobrien	}
192159952Sobrien	printf(": %s", intrstr);
193159952Sobrien
194159952Sobrien	sc->sc_dmat = pa->pa_dmat;
195159952Sobrien
196159952Sobrien	nfe_get_macaddr(sc, sc->sc_arpcom.ac_enaddr);
197159952Sobrien	printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
198159952Sobrien
199159952Sobrien	sc->sc_flags = 0;
200159952Sobrien
201159952Sobrien	switch (PCI_PRODUCT(pa->pa_id)) {
202159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2:
203159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3:
204159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4:
205159952Sobrien	case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5:
206159952Sobrien		sc->sc_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM;
207159952Sobrien		break;
208159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN1:
209159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP51_LAN2:
210159952Sobrien		sc->sc_flags |= NFE_40BIT_ADDR;
211159952Sobrien		break;
212159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN1:
213159952Sobrien	case PCI_PRODUCT_NVIDIA_CK804_LAN2:
214159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN1:
215159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP04_LAN2:
216159952Sobrien		sc->sc_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM;
217159952Sobrien		break;
218159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN1:
219159952Sobrien	case PCI_PRODUCT_NVIDIA_MCP55_LAN2:
220159952Sobrien		sc->sc_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM |
221159952Sobrien		    NFE_HW_VLAN;
222159952Sobrien		break;
223159952Sobrien	}
224159952Sobrien
225159952Sobrien#ifndef NFE_NO_JUMBO
226159952Sobrien	/* enable jumbo frames for adapters that support it */
227159952Sobrien	if (sc->sc_flags & NFE_JUMBO_SUP)
228159952Sobrien		sc->sc_flags |= NFE_USE_JUMBO;
229159952Sobrien#endif
230159952Sobrien
231159952Sobrien	/*
232159952Sobrien	 * Allocate Tx and Rx rings.
233159952Sobrien	 */
234159952Sobrien	if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) {
235159952Sobrien		printf("%s: could not allocate Tx ring\n",
236159952Sobrien		    sc->sc_dev.dv_xname);
237159952Sobrien		return;
238159952Sobrien	}
239159952Sobrien
240159952Sobrien	if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) {
241159952Sobrien		printf("%s: could not allocate Rx ring\n",
242159952Sobrien		    sc->sc_dev.dv_xname);
243159952Sobrien		nfe_free_tx_ring(sc, &sc->txq);
244159952Sobrien		return;
245159952Sobrien	}
246159952Sobrien
247159952Sobrien	ifp = &sc->sc_arpcom.ac_if;
248159952Sobrien	ifp->if_softc = sc;
249159952Sobrien	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
250159952Sobrien	ifp->if_ioctl = nfe_ioctl;
251159952Sobrien	ifp->if_start = nfe_start;
252159952Sobrien	ifp->if_watchdog = nfe_watchdog;
253159952Sobrien	ifp->if_init = nfe_init;
254159952Sobrien	ifp->if_baudrate = IF_Gbps(1);
255159952Sobrien	IFQ_SET_MAXLEN(&ifp->if_snd, NFE_IFQ_MAXLEN);
256159952Sobrien	IFQ_SET_READY(&ifp->if_snd);
257159952Sobrien	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
258159952Sobrien
259159952Sobrien	ifp->if_capabilities = IFCAP_VLAN_MTU;
260159952Sobrien#if NVLAN > 0
261159952Sobrien	if (sc->sc_flags & NFE_HW_VLAN)
262159952Sobrien		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
263159952Sobrien#endif
264159952Sobrien#ifdef NFE_CSUM
265159952Sobrien	if (sc->sc_flags & NFE_HW_CSUM) {
266159952Sobrien		ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
267159952Sobrien		    IFCAP_CSUM_UDPv4;
268159952Sobrien	}
269159952Sobrien#endif
270159952Sobrien
271159952Sobrien	sc->sc_mii.mii_ifp = ifp;
272159952Sobrien	sc->sc_mii.mii_readreg = nfe_miibus_readreg;
273159952Sobrien	sc->sc_mii.mii_writereg = nfe_miibus_writereg;
274159952Sobrien	sc->sc_mii.mii_statchg = nfe_miibus_statchg;
275159952Sobrien
276159952Sobrien	ifmedia_init(&sc->sc_mii.mii_media, 0, nfe_ifmedia_upd,
277159952Sobrien	    nfe_ifmedia_sts);
278159952Sobrien	mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
279159952Sobrien	    MII_OFFSET_ANY, 0);
280159952Sobrien	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
281159952Sobrien		printf("%s: no PHY found!\n", sc->sc_dev.dv_xname);
282159952Sobrien		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL,
283159952Sobrien		    0, NULL);
284159952Sobrien		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL);
285159952Sobrien	} else
286159952Sobrien		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
287159952Sobrien
288159952Sobrien	if_attach(ifp);
289159952Sobrien	ether_ifattach(ifp);
290159952Sobrien
291159952Sobrien	timeout_set(&sc->sc_tick_ch, nfe_tick, sc);
292159952Sobrien
293159952Sobrien	sc->sc_powerhook = powerhook_establish(nfe_power, sc);
294159952Sobrien}
295159952Sobrien
296159952Sobrienvoid
297159952Sobriennfe_power(int why, void *arg)
298159952Sobrien{
299159952Sobrien	struct nfe_softc *sc = arg;
300159952Sobrien	struct ifnet *ifp;
301159952Sobrien
302159952Sobrien	if (why == PWR_RESUME) {
303159952Sobrien		ifp = &sc->sc_arpcom.ac_if;
304159952Sobrien		if (ifp->if_flags & IFF_UP) {
305159952Sobrien			nfe_init(ifp);
306159952Sobrien			if (ifp->if_flags & IFF_RUNNING)
307159952Sobrien				nfe_start(ifp);
308159952Sobrien		}
309159952Sobrien	}
310159952Sobrien}
311159952Sobrien
312159952Sobrienvoid
313159952Sobriennfe_miibus_statchg(struct device *dev)
314159952Sobrien{
315159952Sobrien	struct nfe_softc *sc = (struct nfe_softc *)dev;
316159952Sobrien	struct mii_data *mii = &sc->sc_mii;
317159952Sobrien	uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET;
318159952Sobrien
319159952Sobrien	phy = NFE_READ(sc, NFE_PHY_IFACE);
320159952Sobrien	phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T);
321159952Sobrien
322159952Sobrien	seed = NFE_READ(sc, NFE_RNDSEED);
323159952Sobrien	seed &= ~NFE_SEED_MASK;
324159952Sobrien
325159952Sobrien	if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) {
326159952Sobrien		phy  |= NFE_PHY_HDX;	/* half-duplex */
327159952Sobrien		misc |= NFE_MISC1_HDX;
328159952Sobrien	}
329159952Sobrien
330159952Sobrien	switch (IFM_SUBTYPE(mii->mii_media_active)) {
331159952Sobrien	case IFM_1000_T:	/* full-duplex only */
332159952Sobrien		link |= NFE_MEDIA_1000T;
333159952Sobrien		seed |= NFE_SEED_1000T;
334159952Sobrien		phy  |= NFE_PHY_1000T;
335159952Sobrien		break;
336159952Sobrien	case IFM_100_TX:
337159952Sobrien		link |= NFE_MEDIA_100TX;
338159952Sobrien		seed |= NFE_SEED_100TX;
339159952Sobrien		phy  |= NFE_PHY_100TX;
340159952Sobrien		break;
341159952Sobrien	case IFM_10_T:
342159952Sobrien		link |= NFE_MEDIA_10T;
343159952Sobrien		seed |= NFE_SEED_10T;
344159952Sobrien		break;
345159952Sobrien	}
346159952Sobrien
347159952Sobrien	NFE_WRITE(sc, NFE_RNDSEED, seed);	/* XXX: gigabit NICs only? */
348159952Sobrien
349159952Sobrien	NFE_WRITE(sc, NFE_PHY_IFACE, phy);
350159952Sobrien	NFE_WRITE(sc, NFE_MISC1, misc);
351159952Sobrien	NFE_WRITE(sc, NFE_LINKSPEED, link);
352159952Sobrien}
353159952Sobrien
354159952Sobrienint
355159952Sobriennfe_miibus_readreg(struct device *dev, int phy, int reg)
356159952Sobrien{
357159952Sobrien	struct nfe_softc *sc = (struct nfe_softc *)dev;
358159952Sobrien	uint32_t val;
359159952Sobrien	int ntries;
360159952Sobrien
361159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
362159952Sobrien
363159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
364159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
365159952Sobrien		DELAY(100);
366159952Sobrien	}
367159952Sobrien
368159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg);
369159952Sobrien
370159952Sobrien	for (ntries = 0; ntries < 1000; ntries++) {
371159952Sobrien		DELAY(100);
372159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
373159952Sobrien			break;
374159952Sobrien	}
375159952Sobrien	if (ntries == 1000) {
376159952Sobrien		DPRINTFN(2, ("%s: timeout waiting for PHY\n",
377159952Sobrien		    sc->sc_dev.dv_xname));
378159952Sobrien		return 0;
379159952Sobrien	}
380159952Sobrien
381159952Sobrien	if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) {
382159952Sobrien		DPRINTFN(2, ("%s: could not read PHY\n",
383159952Sobrien		    sc->sc_dev.dv_xname));
384159952Sobrien		return 0;
385159952Sobrien	}
386159952Sobrien
387159952Sobrien	val = NFE_READ(sc, NFE_PHY_DATA);
388159952Sobrien	if (val != 0xffffffff && val != 0)
389159952Sobrien		sc->mii_phyaddr = phy;
390159952Sobrien
391159952Sobrien	DPRINTFN(2, ("%s: mii read phy %d reg 0x%x ret 0x%x\n",
392159952Sobrien	    sc->sc_dev.dv_xname, phy, reg, val));
393159952Sobrien
394159952Sobrien	return val;
395159952Sobrien}
396159952Sobrien
397159952Sobrienvoid
398159952Sobriennfe_miibus_writereg(struct device *dev, int phy, int reg, int val)
399159952Sobrien{
400159952Sobrien	struct nfe_softc *sc = (struct nfe_softc *)dev;
401159952Sobrien	uint32_t ctl;
402159952Sobrien	int ntries;
403159952Sobrien
404159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
405159952Sobrien
406159952Sobrien	if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) {
407159952Sobrien		NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY);
408159952Sobrien		DELAY(100);
409159952Sobrien	}
410159952Sobrien
411159952Sobrien	NFE_WRITE(sc, NFE_PHY_DATA, val);
412159952Sobrien	ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg;
413159952Sobrien	NFE_WRITE(sc, NFE_PHY_CTL, ctl);
414159952Sobrien
415159952Sobrien	for (ntries = 0; ntries < 1000; ntries++) {
416159952Sobrien		DELAY(100);
417159952Sobrien		if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY))
418159952Sobrien			break;
419159952Sobrien	}
420159952Sobrien#ifdef NFE_DEBUG
421159952Sobrien	if (nfedebug >= 2 && ntries == 1000)
422159952Sobrien		printf("could not write to PHY\n");
423159952Sobrien#endif
424159952Sobrien}
425159952Sobrien
426159952Sobrienint
427159952Sobriennfe_intr(void *arg)
428159952Sobrien{
429159952Sobrien	struct nfe_softc *sc = arg;
430159952Sobrien	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
431159952Sobrien	uint32_t r;
432159952Sobrien
433159952Sobrien	if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0)
434159952Sobrien		return 0;	/* not for us */
435159952Sobrien	NFE_WRITE(sc, NFE_IRQ_STATUS, r);
436159952Sobrien
437159952Sobrien	DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r));
438159952Sobrien
439159952Sobrien	if (r & NFE_IRQ_LINK) {
440159952Sobrien		NFE_READ(sc, NFE_PHY_STATUS);
441159952Sobrien		NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
442159952Sobrien		DPRINTF(("%s: link state changed\n", sc->sc_dev.dv_xname));
443159952Sobrien	}
444159952Sobrien
445159952Sobrien	if (ifp->if_flags & IFF_RUNNING) {
446159952Sobrien		/* check Rx ring */
447159952Sobrien		nfe_rxeof(sc);
448159952Sobrien
449159952Sobrien		/* check Tx ring */
450159952Sobrien		nfe_txeof(sc);
451159952Sobrien	}
452159952Sobrien
453159952Sobrien	return 1;
454159952Sobrien}
455159952Sobrien
456159952Sobrienint
457159952Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
458159952Sobrien{
459159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
460159952Sobrien	struct ifreq *ifr = (struct ifreq *)data;
461159952Sobrien	struct ifaddr *ifa = (struct ifaddr *)data;
462159952Sobrien	int s, error = 0;
463159952Sobrien
464159952Sobrien	s = splnet();
465159952Sobrien
466159952Sobrien	if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
467159952Sobrien		splx(s);
468159952Sobrien		return error;
469159952Sobrien	}
470159952Sobrien
471159952Sobrien	switch (cmd) {
472159952Sobrien	case SIOCSIFADDR:
473159952Sobrien		ifp->if_flags |= IFF_UP;
474159952Sobrien		if (!(ifp->if_flags & IFF_RUNNING))
475159952Sobrien			nfe_init(ifp);
476159952Sobrien#ifdef INET
477159952Sobrien		if (ifa->ifa_addr->sa_family == AF_INET)
478159952Sobrien			arp_ifinit(&sc->sc_arpcom, ifa);
479159952Sobrien#endif
480159952Sobrien		break;
481159952Sobrien	case SIOCSIFMTU:
482159952Sobrien		if (ifr->ifr_mtu < ETHERMIN ||
483159952Sobrien		    ((sc->sc_flags & NFE_USE_JUMBO) &&
484159952Sobrien		    ifr->ifr_mtu > ETHERMTU_JUMBO) ||
485159952Sobrien		    (!(sc->sc_flags & NFE_USE_JUMBO) &&
486159952Sobrien		    ifr->ifr_mtu > ETHERMTU))
487159952Sobrien			error = EINVAL;
488159952Sobrien		else if (ifp->if_mtu != ifr->ifr_mtu)
489159952Sobrien			ifp->if_mtu = ifr->ifr_mtu;
490159952Sobrien		break;
491159952Sobrien	case SIOCSIFFLAGS:
492159952Sobrien		if (ifp->if_flags & IFF_UP) {
493159952Sobrien			/*
494159952Sobrien			 * If only the PROMISC or ALLMULTI flag changes, then
495159952Sobrien			 * don't do a full re-init of the chip, just update
496159952Sobrien			 * the Rx filter.
497159952Sobrien			 */
498159952Sobrien			if ((ifp->if_flags & IFF_RUNNING) &&
499159952Sobrien			    ((ifp->if_flags ^ sc->sc_if_flags) &
500159952Sobrien			     (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
501159952Sobrien				nfe_setmulti(sc);
502159952Sobrien			} else {
503159952Sobrien				if (!(ifp->if_flags & IFF_RUNNING))
504159952Sobrien					nfe_init(ifp);
505159952Sobrien			}
506159952Sobrien		} else {
507159952Sobrien			if (ifp->if_flags & IFF_RUNNING)
508159952Sobrien				nfe_stop(ifp, 1);
509159952Sobrien		}
510159952Sobrien		sc->sc_if_flags = ifp->if_flags;
511159952Sobrien		break;
512159952Sobrien	case SIOCADDMULTI:
513159952Sobrien	case SIOCDELMULTI:
514159952Sobrien		error = (cmd == SIOCADDMULTI) ?
515159952Sobrien		    ether_addmulti(ifr, &sc->sc_arpcom) :
516159952Sobrien		    ether_delmulti(ifr, &sc->sc_arpcom);
517159952Sobrien
518159952Sobrien		if (error == ENETRESET) {
519159952Sobrien			if (ifp->if_flags & IFF_RUNNING)
520159952Sobrien				nfe_setmulti(sc);
521159952Sobrien			error = 0;
522159952Sobrien		}
523159952Sobrien		break;
524159952Sobrien	case SIOCSIFMEDIA:
525159952Sobrien	case SIOCGIFMEDIA:
526159952Sobrien		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
527159952Sobrien		break;
528159952Sobrien	default:
529159952Sobrien		error = EINVAL;
530159952Sobrien	}
531159952Sobrien
532159952Sobrien	splx(s);
533159952Sobrien
534159952Sobrien	return error;
535159952Sobrien}
536159952Sobrien
537159952Sobrienvoid
538159952Sobriennfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops)
539159952Sobrien{
540159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->txq.map,
541159952Sobrien	    (caddr_t)desc32 - (caddr_t)sc->txq.desc32,
542159952Sobrien	    sizeof (struct nfe_desc32), ops);
543159952Sobrien}
544159952Sobrien
545159952Sobrienvoid
546159952Sobriennfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops)
547159952Sobrien{
548159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->txq.map,
549159952Sobrien	    (caddr_t)desc64 - (caddr_t)sc->txq.desc64,
550159952Sobrien	    sizeof (struct nfe_desc64), ops);
551159952Sobrien}
552159952Sobrien
553159952Sobrienvoid
554159952Sobriennfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops)
555159952Sobrien{
556159952Sobrien	if (end > start) {
557159952Sobrien		bus_dmamap_sync(sc->sc_dmat, sc->txq.map,
558159952Sobrien		    (caddr_t)&sc->txq.desc32[start] - (caddr_t)sc->txq.desc32,
559159952Sobrien		    (caddr_t)&sc->txq.desc32[end] -
560159952Sobrien		    (caddr_t)&sc->txq.desc32[start], ops);
561159952Sobrien		return;
562159952Sobrien	}
563159952Sobrien	/* sync from 'start' to end of ring */
564159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->txq.map,
565159952Sobrien	    (caddr_t)&sc->txq.desc32[start] - (caddr_t)sc->txq.desc32,
566159952Sobrien	    (caddr_t)&sc->txq.desc32[NFE_TX_RING_COUNT] -
567159952Sobrien	    (caddr_t)&sc->txq.desc32[start], ops);
568159952Sobrien
569159952Sobrien	/* sync from start of ring to 'end' */
570159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 0,
571159952Sobrien	    (caddr_t)&sc->txq.desc32[end] - (caddr_t)sc->txq.desc32, ops);
572159952Sobrien}
573159952Sobrien
574159952Sobrienvoid
575159952Sobriennfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops)
576159952Sobrien{
577159952Sobrien	if (end > start) {
578159952Sobrien		bus_dmamap_sync(sc->sc_dmat, sc->txq.map,
579159952Sobrien		    (caddr_t)&sc->txq.desc64[start] - (caddr_t)sc->txq.desc64,
580159952Sobrien		    (caddr_t)&sc->txq.desc64[end] -
581159952Sobrien		    (caddr_t)&sc->txq.desc64[start], ops);
582159952Sobrien		return;
583159952Sobrien	}
584159952Sobrien	/* sync from 'start' to end of ring */
585159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->txq.map,
586159952Sobrien	    (caddr_t)&sc->txq.desc64[start] - (caddr_t)sc->txq.desc64,
587159952Sobrien	    (caddr_t)&sc->txq.desc64[NFE_TX_RING_COUNT] -
588159952Sobrien	    (caddr_t)&sc->txq.desc64[start], ops);
589159952Sobrien
590159952Sobrien	/* sync from start of ring to 'end' */
591159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 0,
592159952Sobrien	    (caddr_t)&sc->txq.desc64[end] - (caddr_t)sc->txq.desc64, ops);
593159952Sobrien}
594159952Sobrien
595159952Sobrienvoid
596159952Sobriennfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops)
597159952Sobrien{
598159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->rxq.map,
599159952Sobrien	    (caddr_t)desc32 - (caddr_t)sc->rxq.desc32,
600159952Sobrien	    sizeof (struct nfe_desc32), ops);
601159952Sobrien}
602159952Sobrien
603159952Sobrienvoid
604159952Sobriennfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops)
605159952Sobrien{
606159952Sobrien	bus_dmamap_sync(sc->sc_dmat, sc->rxq.map,
607159952Sobrien	    (caddr_t)desc64 - (caddr_t)sc->rxq.desc64,
608159952Sobrien	    sizeof (struct nfe_desc64), ops);
609159952Sobrien}
610159952Sobrien
611159952Sobrienvoid
612159952Sobriennfe_rxeof(struct nfe_softc *sc)
613159952Sobrien{
614159952Sobrien	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
615159952Sobrien	struct nfe_desc32 *desc32;
616159952Sobrien	struct nfe_desc64 *desc64;
617159952Sobrien	struct nfe_rx_data *data;
618159952Sobrien	struct nfe_jbuf *jbuf;
619159952Sobrien	struct mbuf *m, *mnew;
620159952Sobrien	bus_addr_t physaddr;
621159952Sobrien	uint16_t flags;
622159952Sobrien	int error, len;
623159952Sobrien
624159952Sobrien	for (;;) {
625159952Sobrien		data = &sc->rxq.data[sc->rxq.cur];
626159952Sobrien
627159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR) {
628159952Sobrien			desc64 = &sc->rxq.desc64[sc->rxq.cur];
629159952Sobrien			nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD);
630159952Sobrien
631159952Sobrien			flags = letoh16(desc64->flags);
632159952Sobrien			len = letoh16(desc64->length) & 0x3fff;
633159952Sobrien		} else {
634159952Sobrien			desc32 = &sc->rxq.desc32[sc->rxq.cur];
635159952Sobrien			nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD);
636159952Sobrien
637159952Sobrien			flags = letoh16(desc32->flags);
638159952Sobrien			len = letoh16(desc32->length) & 0x3fff;
639159952Sobrien		}
640159952Sobrien
641159952Sobrien		if (flags & NFE_RX_READY)
642159952Sobrien			break;
643159952Sobrien
644159952Sobrien		if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
645159952Sobrien			if (!(flags & NFE_RX_VALID_V1))
646159952Sobrien				goto skip;
647159952Sobrien
648159952Sobrien			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
649159952Sobrien				flags &= ~NFE_RX_ERROR;
650159952Sobrien				len--;	/* fix buffer length */
651159952Sobrien			}
652159952Sobrien		} else {
653159952Sobrien			if (!(flags & NFE_RX_VALID_V2))
654159952Sobrien				goto skip;
655159952Sobrien
656159952Sobrien			if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) {
657159952Sobrien				flags &= ~NFE_RX_ERROR;
658159952Sobrien				len--;	/* fix buffer length */
659159952Sobrien			}
660159952Sobrien		}
661159952Sobrien
662159952Sobrien		if (flags & NFE_RX_ERROR) {
663159952Sobrien			ifp->if_ierrors++;
664159952Sobrien			goto skip;
665159952Sobrien		}
666159952Sobrien
667159952Sobrien		/*
668159952Sobrien		 * Try to allocate a new mbuf for this ring element and load
669159952Sobrien		 * it before processing the current mbuf. If the ring element
670159952Sobrien		 * cannot be loaded, drop the received packet and reuse the
671159952Sobrien		 * old mbuf. In the unlikely case that the old mbuf can't be
672159952Sobrien		 * reloaded either, explicitly panic.
673159952Sobrien		 */
674159952Sobrien		MGETHDR(mnew, M_DONTWAIT, MT_DATA);
675159952Sobrien		if (mnew == NULL) {
676159952Sobrien			ifp->if_ierrors++;
677159952Sobrien			goto skip;
678159952Sobrien		}
679159952Sobrien
680159952Sobrien		if (sc->sc_flags & NFE_USE_JUMBO) {
681159952Sobrien			if ((jbuf = nfe_jalloc(sc)) == NULL) {
682159952Sobrien				m_freem(mnew);
683159952Sobrien				ifp->if_ierrors++;
684159952Sobrien				goto skip;
685159952Sobrien			}
686159952Sobrien			MEXTADD(mnew, jbuf->buf, NFE_JBYTES, 0, nfe_jfree, sc);
687159952Sobrien
688159952Sobrien			bus_dmamap_sync(sc->sc_dmat, sc->rxq.jmap,
689159952Sobrien			    mtod(data->m, caddr_t) - sc->rxq.jpool, NFE_JBYTES,
690159952Sobrien			    BUS_DMASYNC_POSTREAD);
691159952Sobrien
692159952Sobrien			physaddr = jbuf->physaddr;
693159952Sobrien		} else {
694159952Sobrien			MCLGET(mnew, M_DONTWAIT);
695159952Sobrien			if (!(mnew->m_flags & M_EXT)) {
696159952Sobrien				m_freem(mnew);
697159952Sobrien				ifp->if_ierrors++;
698159952Sobrien				goto skip;
699159952Sobrien			}
700159952Sobrien
701159952Sobrien			bus_dmamap_sync(sc->sc_dmat, data->map, 0,
702159952Sobrien			    data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
703159952Sobrien			bus_dmamap_unload(sc->sc_dmat, data->map);
704159952Sobrien
705159952Sobrien			error = bus_dmamap_load(sc->sc_dmat, data->map,
706159952Sobrien			    mtod(mnew, void *), MCLBYTES, NULL,
707159952Sobrien			    BUS_DMA_READ | BUS_DMA_NOWAIT);
708159952Sobrien			if (error != 0) {
709159952Sobrien				m_freem(mnew);
710159952Sobrien
711159952Sobrien				/* try to reload the old mbuf */
712159952Sobrien				error = bus_dmamap_load(sc->sc_dmat, data->map,
713159952Sobrien				    mtod(data->m, void *), MCLBYTES, NULL,
714159952Sobrien				    BUS_DMA_READ | BUS_DMA_NOWAIT);
715159952Sobrien				if (error != 0) {
716159952Sobrien					/* very unlikely that it will fail.. */
717159952Sobrien					panic("%s: could not load old rx mbuf",
718159952Sobrien					    sc->sc_dev.dv_xname);
719159952Sobrien				}
720159952Sobrien				ifp->if_ierrors++;
721159952Sobrien				goto skip;
722159952Sobrien			}
723159952Sobrien			physaddr = data->map->dm_segs[0].ds_addr;
724159952Sobrien		}
725159952Sobrien
726159952Sobrien		/*
727159952Sobrien		 * New mbuf successfully loaded, update Rx ring and continue
728159952Sobrien		 * processing.
729159952Sobrien		 */
730159952Sobrien		m = data->m;
731159952Sobrien		data->m = mnew;
732159952Sobrien
733159952Sobrien		/* finalize mbuf */
734159952Sobrien		m->m_pkthdr.len = m->m_len = len;
735159952Sobrien		m->m_pkthdr.rcvif = ifp;
736159952Sobrien
737159952Sobrien#ifdef notyet
738159952Sobrien		if (sc->sc_flags & NFE_HW_CSUM) {
739159952Sobrien			if (flags & NFE_RX_IP_CSUMOK)
740159952Sobrien				m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
741159952Sobrien			if (flags & NFE_RX_UDP_CSUMOK)
742159952Sobrien				m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
743159952Sobrien			if (flags & NFE_RX_TCP_CSUMOK)
744159952Sobrien				m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
745159952Sobrien		}
746159952Sobrien#elif defined(NFE_CSUM)
747159952Sobrien		if ((sc->sc_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK))
748159952Sobrien			m->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK;
749159952Sobrien#endif
750159952Sobrien
751159952Sobrien#if NBPFILTER > 0
752159952Sobrien		if (ifp->if_bpf)
753159952Sobrien			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
754159952Sobrien#endif
755159952Sobrien		ifp->if_ipackets++;
756159952Sobrien		ether_input_mbuf(ifp, m);
757159952Sobrien
758159952Sobrien		/* update mapping address in h/w descriptor */
759159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR) {
760159952Sobrien#if defined(__LP64__)
761159952Sobrien			desc64->physaddr[0] = htole32(physaddr >> 32);
762159952Sobrien#endif
763159952Sobrien			desc64->physaddr[1] = htole32(physaddr & 0xffffffff);
764159952Sobrien		} else {
765159952Sobrien			desc32->physaddr = htole32(physaddr);
766159952Sobrien		}
767159952Sobrien
768159952Sobrienskip:		if (sc->sc_flags & NFE_40BIT_ADDR) {
769159952Sobrien			desc64->length = htole16(sc->rxq.bufsz);
770159952Sobrien			desc64->flags = htole16(NFE_RX_READY);
771159952Sobrien
772159952Sobrien			nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE);
773159952Sobrien		} else {
774159952Sobrien			desc32->length = htole16(sc->rxq.bufsz);
775159952Sobrien			desc32->flags = htole16(NFE_RX_READY);
776159952Sobrien
777159952Sobrien			nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE);
778159952Sobrien		}
779159952Sobrien
780159952Sobrien		sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT;
781159952Sobrien	}
782159952Sobrien}
783159952Sobrien
784159952Sobrienvoid
785159952Sobriennfe_txeof(struct nfe_softc *sc)
786159952Sobrien{
787159952Sobrien	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
788159952Sobrien	struct nfe_desc32 *desc32;
789159952Sobrien	struct nfe_desc64 *desc64;
790159952Sobrien	struct nfe_tx_data *data = NULL;
791159952Sobrien	uint16_t flags;
792159952Sobrien
793159952Sobrien	while (sc->txq.next != sc->txq.cur) {
794159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR) {
795159952Sobrien			desc64 = &sc->txq.desc64[sc->txq.next];
796159952Sobrien			nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD);
797159952Sobrien
798159952Sobrien			flags = letoh16(desc64->flags);
799159952Sobrien		} else {
800159952Sobrien			desc32 = &sc->txq.desc32[sc->txq.next];
801159952Sobrien			nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD);
802159952Sobrien
803159952Sobrien			flags = letoh16(desc32->flags);
804159952Sobrien		}
805159952Sobrien
806159952Sobrien		if (flags & NFE_TX_VALID)
807159952Sobrien			break;
808159952Sobrien
809159952Sobrien		data = &sc->txq.data[sc->txq.next];
810159952Sobrien
811159952Sobrien		if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
812159952Sobrien			if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL)
813159952Sobrien				goto skip;
814159952Sobrien
815159952Sobrien			if ((flags & NFE_TX_ERROR_V1) != 0) {
816159952Sobrien				printf("%s: tx v1 error 0x%04b\n",
817159952Sobrien				    sc->sc_dev.dv_xname, flags, NFE_V1_TXERR);
818159952Sobrien				ifp->if_oerrors++;
819159952Sobrien			} else
820159952Sobrien				ifp->if_opackets++;
821159952Sobrien		} else {
822159952Sobrien			if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL)
823159952Sobrien				goto skip;
824159952Sobrien
825159952Sobrien			if ((flags & NFE_TX_ERROR_V2) != 0) {
826159952Sobrien				printf("%s: tx v2 error 0x%04b\n",
827159952Sobrien				    sc->sc_dev.dv_xname, flags, NFE_V2_TXERR);
828159952Sobrien				ifp->if_oerrors++;
829159952Sobrien			} else
830159952Sobrien				ifp->if_opackets++;
831159952Sobrien		}
832159952Sobrien
833159952Sobrien		if (data->m == NULL) {	/* should not get there */
834159952Sobrien			printf("%s: last fragment bit w/o associated mbuf!\n",
835159952Sobrien			    sc->sc_dev.dv_xname);
836159952Sobrien			goto skip;
837159952Sobrien		}
838159952Sobrien
839159952Sobrien		/* last fragment of the mbuf chain transmitted */
840159952Sobrien		bus_dmamap_sync(sc->sc_dmat, data->active, 0,
841159952Sobrien		    data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
842159952Sobrien		bus_dmamap_unload(sc->sc_dmat, data->active);
843159952Sobrien		m_freem(data->m);
844159952Sobrien		data->m = NULL;
845159952Sobrien
846159952Sobrien		ifp->if_timer = 0;
847159952Sobrien
848159952Sobrienskip:		sc->txq.queued--;
849159952Sobrien		sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT;
850159952Sobrien	}
851159952Sobrien
852159952Sobrien	if (data != NULL) {	/* at least one slot freed */
853159952Sobrien		ifp->if_flags &= ~IFF_OACTIVE;
854159952Sobrien		nfe_start(ifp);
855159952Sobrien	}
856159952Sobrien}
857159952Sobrien
858159952Sobrienint
859159952Sobriennfe_encap(struct nfe_softc *sc, struct mbuf *m0)
860159952Sobrien{
861159952Sobrien	struct nfe_desc32 *desc32;
862159952Sobrien	struct nfe_desc64 *desc64;
863159952Sobrien	struct nfe_tx_data *data;
864159952Sobrien	bus_dmamap_t map;
865159952Sobrien	uint16_t flags = NFE_TX_VALID;
866159952Sobrien#if NVLAN > 0
867159952Sobrien	uint32_t vtag = 0;
868159952Sobrien#endif
869159952Sobrien	int error, i;
870159952Sobrien
871159952Sobrien	map = sc->txq.data[sc->txq.cur].map;
872159952Sobrien
873159952Sobrien	error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, BUS_DMA_NOWAIT);
874159952Sobrien	if (error != 0) {
875159952Sobrien		printf("%s: could not map mbuf (error %d)\n",
876159952Sobrien		    sc->sc_dev.dv_xname, error);
877159952Sobrien		return error;
878159952Sobrien	}
879159952Sobrien
880159952Sobrien	if (sc->txq.queued + map->dm_nsegs >= NFE_TX_RING_COUNT - 1) {
881159952Sobrien		bus_dmamap_unload(sc->sc_dmat, map);
882159952Sobrien		return ENOBUFS;
883159952Sobrien	}
884159952Sobrien
885159952Sobrien#if NVLAN > 0
886159952Sobrien	/* setup h/w VLAN tagging */
887159952Sobrien	if ((m0->m_flags & (M_PROTO1 | M_PKTHDR)) == (M_PROTO1 | M_PKTHDR) &&
888159952Sobrien	    m0->m_pkthdr.rcvif != NULL) {
889159952Sobrien		struct ifvlan *ifv = m0->m_pkthdr.rcvif->if_softc;
890159952Sobrien		vtag = NFE_TX_VTAG | htons(ifv->ifv_tag);
891159952Sobrien	}
892159952Sobrien#endif
893159952Sobrien#ifdef NFE_CSUM
894159952Sobrien	if (m0->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
895159952Sobrien		flags |= NFE_TX_IP_CSUM;
896159952Sobrien	if (m0->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT))
897159952Sobrien		flags |= NFE_TX_TCP_CSUM;
898159952Sobrien#endif
899159952Sobrien
900159952Sobrien	for (i = 0; i < map->dm_nsegs; i++) {
901159952Sobrien		data = &sc->txq.data[sc->txq.cur];
902159952Sobrien
903159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR) {
904159952Sobrien			desc64 = &sc->txq.desc64[sc->txq.cur];
905159952Sobrien#if defined(__LP64__)
906159952Sobrien			desc64->physaddr[0] =
907159952Sobrien			    htole32(map->dm_segs[i].ds_addr >> 32);
908159952Sobrien#endif
909159952Sobrien			desc64->physaddr[1] =
910159952Sobrien			    htole32(map->dm_segs[i].ds_addr & 0xffffffff);
911159952Sobrien			desc64->length = htole16(map->dm_segs[i].ds_len - 1);
912159952Sobrien			desc64->flags = htole16(flags);
913159952Sobrien#if NVLAN > 0
914159952Sobrien			desc64->vtag = htole32(vtag);
915159952Sobrien#endif
916159952Sobrien		} else {
917159952Sobrien			desc32 = &sc->txq.desc32[sc->txq.cur];
918159952Sobrien
919159952Sobrien			desc32->physaddr = htole32(map->dm_segs[i].ds_addr);
920159952Sobrien			desc32->length = htole16(map->dm_segs[i].ds_len - 1);
921159952Sobrien			desc32->flags = htole16(flags);
922159952Sobrien		}
923159952Sobrien
924159952Sobrien		/* csum flags and vtag belong to the first fragment only */
925159952Sobrien		if (map->dm_nsegs > 1) {
926159952Sobrien			flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM);
927159952Sobrien#if NVLAN > 0
928159952Sobrien			vtag = 0;
929159952Sobrien#endif
930159952Sobrien		}
931159952Sobrien
932159952Sobrien		sc->txq.queued++;
933159952Sobrien		sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT;
934159952Sobrien	}
935159952Sobrien
936159952Sobrien	/* the whole mbuf chain has been DMA mapped, fix last descriptor */
937159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR) {
938159952Sobrien		flags |= NFE_TX_LASTFRAG_V2;
939159952Sobrien		desc64->flags = htole16(flags);
940159952Sobrien	} else {
941159952Sobrien		if (sc->sc_flags & NFE_JUMBO_SUP)
942159952Sobrien			flags |= NFE_TX_LASTFRAG_V2;
943159952Sobrien		else
944159952Sobrien			flags |= NFE_TX_LASTFRAG_V1;
945159952Sobrien		desc32->flags = htole16(flags);
946159952Sobrien	}
947159952Sobrien
948159952Sobrien	data->m = m0;
949159952Sobrien	data->active = map;
950159952Sobrien
951159952Sobrien	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
952159952Sobrien	    BUS_DMASYNC_PREWRITE);
953159952Sobrien
954159952Sobrien	return 0;
955159952Sobrien}
956159952Sobrien
957159952Sobrienvoid
958159952Sobriennfe_start(struct ifnet *ifp)
959159952Sobrien{
960159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
961159952Sobrien	int old = sc->txq.cur;
962159952Sobrien	struct mbuf *m0;
963159952Sobrien
964159952Sobrien	for (;;) {
965159952Sobrien		IFQ_POLL(&ifp->if_snd, m0);
966159952Sobrien		if (m0 == NULL)
967159952Sobrien			break;
968159952Sobrien
969159952Sobrien		if (nfe_encap(sc, m0) != 0) {
970159952Sobrien			ifp->if_flags |= IFF_OACTIVE;
971159952Sobrien			break;
972159952Sobrien		}
973159952Sobrien
974159952Sobrien		/* packet put in h/w queue, remove from s/w queue */
975159952Sobrien		IFQ_DEQUEUE(&ifp->if_snd, m0);
976159952Sobrien
977159952Sobrien#if NBPFILTER > 0
978159952Sobrien		if (ifp->if_bpf != NULL)
979159952Sobrien			bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
980159952Sobrien#endif
981159952Sobrien	}
982159952Sobrien	if (sc->txq.cur == old)	/* nothing sent */
983159952Sobrien		return;
984159952Sobrien
985159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR)
986159952Sobrien		nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE);
987159952Sobrien	else
988159952Sobrien		nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE);
989159952Sobrien
990159952Sobrien	/* kick Tx */
991159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl);
992159952Sobrien
993159952Sobrien	/*
994159952Sobrien	 * Set a timeout in case the chip goes out to lunch.
995159952Sobrien	 */
996159952Sobrien	ifp->if_timer = 5;
997159952Sobrien}
998159952Sobrien
999159952Sobrienvoid
1000159952Sobriennfe_watchdog(struct ifnet *ifp)
1001159952Sobrien{
1002159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1003159952Sobrien
1004159952Sobrien	printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
1005159952Sobrien
1006159952Sobrien	nfe_init(ifp);
1007159952Sobrien
1008159952Sobrien	ifp->if_oerrors++;
1009159952Sobrien}
1010159952Sobrien
1011159952Sobrienint
1012159952Sobriennfe_init(struct ifnet *ifp)
1013159952Sobrien{
1014159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1015159952Sobrien	uint32_t tmp;
1016159952Sobrien
1017159952Sobrien	nfe_stop(ifp, 0);
1018159952Sobrien
1019159952Sobrien	NFE_WRITE(sc, NFE_TX_UNK, 0);
1020159952Sobrien	NFE_WRITE(sc, NFE_STATUS, 0);
1021159952Sobrien
1022159952Sobrien	sc->rxtxctl = NFE_RXTX_BIT2;
1023159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR)
1024159952Sobrien		sc->rxtxctl |= NFE_RXTX_V3MAGIC;
1025159952Sobrien	else if (sc->sc_flags & NFE_JUMBO_SUP)
1026159952Sobrien		sc->rxtxctl |= NFE_RXTX_V2MAGIC;
1027159952Sobrien#ifdef NFE_CSUM
1028159952Sobrien	if (sc->sc_flags & NFE_HW_CSUM)
1029159952Sobrien		sc->rxtxctl |= NFE_RXTX_RXCSUM;
1030159952Sobrien#endif
1031159952Sobrien#if NVLAN > 0
1032159952Sobrien	/*
1033159952Sobrien	 * Although the adapter is capable of stripping VLAN tags from received
1034159952Sobrien	 * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on
1035159952Sobrien	 * purpose.  This will be done in software by our network stack.
1036159952Sobrien	 */
1037159952Sobrien	if (sc->sc_flags & NFE_HW_VLAN)
1038159952Sobrien		sc->rxtxctl |= NFE_RXTX_VTAG_INSERT;
1039159952Sobrien#endif
1040159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl);
1041159952Sobrien	DELAY(10);
1042159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
1043159952Sobrien
1044159952Sobrien#if NVLAN
1045159952Sobrien	if (sc->sc_flags & NFE_HW_VLAN)
1046159952Sobrien		NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE);
1047159952Sobrien#endif
1048159952Sobrien
1049159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, 0);
1050159952Sobrien
1051159952Sobrien	/* set MAC address */
1052159952Sobrien	nfe_set_macaddr(sc, sc->sc_arpcom.ac_enaddr);
1053159952Sobrien
1054159952Sobrien	/* tell MAC where rings are in memory */
1055159952Sobrien#ifdef __LP64__
1056159952Sobrien	NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32);
1057159952Sobrien#endif
1058159952Sobrien	NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff);
1059159952Sobrien#ifdef __LP64__
1060159952Sobrien	NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32);
1061159952Sobrien#endif
1062159952Sobrien	NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff);
1063159952Sobrien
1064159952Sobrien	NFE_WRITE(sc, NFE_RING_SIZE,
1065159952Sobrien	    (NFE_RX_RING_COUNT - 1) << 16 |
1066159952Sobrien	    (NFE_TX_RING_COUNT - 1));
1067159952Sobrien
1068159952Sobrien	NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz);
1069159952Sobrien
1070159952Sobrien	/* force MAC to wakeup */
1071159952Sobrien	tmp = NFE_READ(sc, NFE_PWR_STATE);
1072159952Sobrien	NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP);
1073159952Sobrien	DELAY(10);
1074159952Sobrien	tmp = NFE_READ(sc, NFE_PWR_STATE);
1075159952Sobrien	NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID);
1076159952Sobrien
1077159952Sobrien#if 1
1078159952Sobrien	/* configure interrupts coalescing/mitigation */
1079159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT);
1080159952Sobrien#else
1081159952Sobrien	/* no interrupt mitigation: one interrupt per packet */
1082159952Sobrien	NFE_WRITE(sc, NFE_IMTIMER, 970);
1083159952Sobrien#endif
1084159952Sobrien
1085159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC);
1086159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC);
1087159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC);
1088159952Sobrien
1089159952Sobrien	/* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */
1090159952Sobrien	NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC);
1091159952Sobrien
1092159952Sobrien	NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC);
1093159952Sobrien	NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC);
1094159952Sobrien
1095159952Sobrien	sc->rxtxctl &= ~NFE_RXTX_BIT2;
1096159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl);
1097159952Sobrien	DELAY(10);
1098159952Sobrien	NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl);
1099159952Sobrien
1100159952Sobrien	/* set Rx filter */
1101159952Sobrien	nfe_setmulti(sc);
1102159952Sobrien
1103159952Sobrien	nfe_ifmedia_upd(ifp);
1104159952Sobrien
1105159952Sobrien	/* enable Rx */
1106159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START);
1107159952Sobrien
1108159952Sobrien	/* enable Tx */
1109159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START);
1110159952Sobrien
1111159952Sobrien	NFE_WRITE(sc, NFE_PHY_STATUS, 0xf);
1112159952Sobrien
1113159952Sobrien	/* enable interrupts */
1114159952Sobrien	NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED);
1115159952Sobrien
1116159952Sobrien	timeout_add(&sc->sc_tick_ch, hz);
1117159952Sobrien
1118159952Sobrien	ifp->if_flags |= IFF_RUNNING;
1119159952Sobrien	ifp->if_flags &= ~IFF_OACTIVE;
1120159952Sobrien
1121159952Sobrien	return 0;
1122159952Sobrien}
1123159952Sobrien
1124159952Sobrienvoid
1125159952Sobriennfe_stop(struct ifnet *ifp, int disable)
1126159952Sobrien{
1127159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1128159952Sobrien
1129159952Sobrien	timeout_del(&sc->sc_tick_ch);
1130159952Sobrien
1131159952Sobrien	ifp->if_timer = 0;
1132159952Sobrien	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1133159952Sobrien
1134159952Sobrien	mii_down(&sc->sc_mii);
1135159952Sobrien
1136159952Sobrien	/* abort Tx */
1137159952Sobrien	NFE_WRITE(sc, NFE_TX_CTL, 0);
1138159952Sobrien
1139159952Sobrien	/* disable Rx */
1140159952Sobrien	NFE_WRITE(sc, NFE_RX_CTL, 0);
1141159952Sobrien
1142159952Sobrien	/* disable interrupts */
1143159952Sobrien	NFE_WRITE(sc, NFE_IRQ_MASK, 0);
1144159952Sobrien
1145159952Sobrien	/* reset Tx and Rx rings */
1146159952Sobrien	nfe_reset_tx_ring(sc, &sc->txq);
1147159952Sobrien	nfe_reset_rx_ring(sc, &sc->rxq);
1148159952Sobrien}
1149159952Sobrien
1150159952Sobrienint
1151159952Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1152159952Sobrien{
1153159952Sobrien	struct nfe_desc32 *desc32;
1154159952Sobrien	struct nfe_desc64 *desc64;
1155159952Sobrien	struct nfe_rx_data *data;
1156159952Sobrien	struct nfe_jbuf *jbuf;
1157159952Sobrien	void **desc;
1158159952Sobrien	bus_addr_t physaddr;
1159159952Sobrien	int i, nsegs, error, descsize;
1160159952Sobrien
1161159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR) {
1162159952Sobrien		desc = (void **)&ring->desc64;
1163159952Sobrien		descsize = sizeof (struct nfe_desc64);
1164159952Sobrien	} else {
1165159952Sobrien		desc = (void **)&ring->desc32;
1166159952Sobrien		descsize = sizeof (struct nfe_desc32);
1167159952Sobrien	}
1168159952Sobrien
1169159952Sobrien	ring->cur = ring->next = 0;
1170159952Sobrien	ring->bufsz = MCLBYTES;
1171159952Sobrien
1172159952Sobrien	error = bus_dmamap_create(sc->sc_dmat, NFE_RX_RING_COUNT * descsize, 1,
1173159952Sobrien	    NFE_RX_RING_COUNT * descsize, 0, BUS_DMA_NOWAIT, &ring->map);
1174159952Sobrien	if (error != 0) {
1175159952Sobrien		printf("%s: could not create desc DMA map\n",
1176159952Sobrien		    sc->sc_dev.dv_xname);
1177159952Sobrien		goto fail;
1178159952Sobrien	}
1179159952Sobrien
1180159952Sobrien	error = bus_dmamem_alloc(sc->sc_dmat, NFE_RX_RING_COUNT * descsize,
1181159952Sobrien	    PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT);
1182159952Sobrien	if (error != 0) {
1183159952Sobrien		printf("%s: could not allocate DMA memory\n",
1184159952Sobrien		    sc->sc_dev.dv_xname);
1185159952Sobrien		goto fail;
1186159952Sobrien	}
1187159952Sobrien
1188159952Sobrien	error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs,
1189159952Sobrien	    NFE_RX_RING_COUNT * descsize, (caddr_t *)desc, BUS_DMA_NOWAIT);
1190159952Sobrien	if (error != 0) {
1191159952Sobrien		printf("%s: could not map desc DMA memory\n",
1192159952Sobrien		    sc->sc_dev.dv_xname);
1193159952Sobrien		goto fail;
1194159952Sobrien	}
1195159952Sobrien
1196159952Sobrien	error = bus_dmamap_load(sc->sc_dmat, ring->map, *desc,
1197159952Sobrien	    NFE_RX_RING_COUNT * descsize, NULL, BUS_DMA_NOWAIT);
1198159952Sobrien	if (error != 0) {
1199159952Sobrien		printf("%s: could not load desc DMA map\n",
1200159952Sobrien		    sc->sc_dev.dv_xname);
1201159952Sobrien		goto fail;
1202159952Sobrien	}
1203159952Sobrien
1204159952Sobrien	bzero(*desc, NFE_RX_RING_COUNT * descsize);
1205159952Sobrien	ring->physaddr = ring->map->dm_segs[0].ds_addr;
1206159952Sobrien
1207159952Sobrien	if (sc->sc_flags & NFE_USE_JUMBO) {
1208159952Sobrien		ring->bufsz = NFE_JBYTES;
1209159952Sobrien		if ((error = nfe_jpool_alloc(sc)) != 0) {
1210159952Sobrien			printf("%s: could not allocate jumbo frames\n",
1211159952Sobrien			    sc->sc_dev.dv_xname);
1212159952Sobrien			goto fail;
1213159952Sobrien		}
1214159952Sobrien	}
1215159952Sobrien
1216159952Sobrien	/*
1217159952Sobrien	 * Pre-allocate Rx buffers and populate Rx ring.
1218159952Sobrien	 */
1219159952Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1220159952Sobrien		data = &sc->rxq.data[i];
1221159952Sobrien
1222159952Sobrien		MGETHDR(data->m, M_DONTWAIT, MT_DATA);
1223159952Sobrien		if (data->m == NULL) {
1224159952Sobrien			printf("%s: could not allocate rx mbuf\n",
1225159952Sobrien			    sc->sc_dev.dv_xname);
1226159952Sobrien			error = ENOMEM;
1227159952Sobrien			goto fail;
1228159952Sobrien		}
1229159952Sobrien
1230159952Sobrien		if (sc->sc_flags & NFE_USE_JUMBO) {
1231159952Sobrien			if ((jbuf = nfe_jalloc(sc)) == NULL) {
1232159952Sobrien				printf("%s: could not allocate jumbo buffer\n",
1233159952Sobrien				    sc->sc_dev.dv_xname);
1234159952Sobrien				goto fail;
1235159952Sobrien			}
1236159952Sobrien			MEXTADD(data->m, jbuf->buf, NFE_JBYTES, 0, nfe_jfree,
1237159952Sobrien			    sc);
1238159952Sobrien
1239159952Sobrien			physaddr = jbuf->physaddr;
1240159952Sobrien		} else {
1241159952Sobrien			error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
1242159952Sobrien			    MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map);
1243159952Sobrien			if (error != 0) {
1244159952Sobrien				printf("%s: could not create DMA map\n",
1245159952Sobrien				    sc->sc_dev.dv_xname);
1246159952Sobrien				goto fail;
1247159952Sobrien			}
1248159952Sobrien			MCLGET(data->m, M_DONTWAIT);
1249159952Sobrien			if (!(data->m->m_flags & M_EXT)) {
1250159952Sobrien				printf("%s: could not allocate mbuf cluster\n",
1251159952Sobrien				    sc->sc_dev.dv_xname);
1252159952Sobrien				error = ENOMEM;
1253159952Sobrien				goto fail;
1254159952Sobrien			}
1255159952Sobrien
1256159952Sobrien			error = bus_dmamap_load(sc->sc_dmat, data->map,
1257159952Sobrien			    mtod(data->m, void *), MCLBYTES, NULL,
1258159952Sobrien			    BUS_DMA_READ | BUS_DMA_NOWAIT);
1259159952Sobrien			if (error != 0) {
1260159952Sobrien				printf("%s: could not load rx buf DMA map",
1261159952Sobrien				    sc->sc_dev.dv_xname);
1262159952Sobrien				goto fail;
1263159952Sobrien			}
1264159952Sobrien			physaddr = data->map->dm_segs[0].ds_addr;
1265159952Sobrien		}
1266159952Sobrien
1267159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR) {
1268159952Sobrien			desc64 = &sc->rxq.desc64[i];
1269159952Sobrien#if defined(__LP64__)
1270159952Sobrien			desc64->physaddr[0] = htole32(physaddr >> 32);
1271159952Sobrien#endif
1272159952Sobrien			desc64->physaddr[1] = htole32(physaddr & 0xffffffff);
1273159952Sobrien			desc64->length = htole16(sc->rxq.bufsz);
1274159952Sobrien			desc64->flags = htole16(NFE_RX_READY);
1275159952Sobrien		} else {
1276159952Sobrien			desc32 = &sc->rxq.desc32[i];
1277159952Sobrien			desc32->physaddr = htole32(physaddr);
1278159952Sobrien			desc32->length = htole16(sc->rxq.bufsz);
1279159952Sobrien			desc32->flags = htole16(NFE_RX_READY);
1280159952Sobrien		}
1281159952Sobrien	}
1282159952Sobrien
1283159952Sobrien	bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize,
1284159952Sobrien	    BUS_DMASYNC_PREWRITE);
1285159952Sobrien
1286159952Sobrien	return 0;
1287159952Sobrien
1288159952Sobrienfail:	nfe_free_rx_ring(sc, ring);
1289159952Sobrien	return error;
1290159952Sobrien}
1291159952Sobrien
1292159952Sobrienvoid
1293159952Sobriennfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1294159952Sobrien{
1295159952Sobrien	int i;
1296159952Sobrien
1297159952Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1298159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR) {
1299159952Sobrien			ring->desc64[i].length = htole16(ring->bufsz);
1300159952Sobrien			ring->desc64[i].flags = htole16(NFE_RX_READY);
1301159952Sobrien		} else {
1302159952Sobrien			ring->desc32[i].length = htole16(ring->bufsz);
1303159952Sobrien			ring->desc32[i].flags = htole16(NFE_RX_READY);
1304159952Sobrien		}
1305159952Sobrien	}
1306159952Sobrien
1307159952Sobrien	bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize,
1308159952Sobrien	    BUS_DMASYNC_PREWRITE);
1309159952Sobrien
1310159952Sobrien	ring->cur = ring->next = 0;
1311159952Sobrien}
1312159952Sobrien
1313159952Sobrienvoid
1314159952Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
1315159952Sobrien{
1316159952Sobrien	struct nfe_rx_data *data;
1317159952Sobrien	void *desc;
1318159952Sobrien	int i, descsize;
1319159952Sobrien
1320159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR) {
1321159952Sobrien		desc = ring->desc64;
1322159952Sobrien		descsize = sizeof (struct nfe_desc64);
1323159952Sobrien	} else {
1324159952Sobrien		desc = ring->desc32;
1325159952Sobrien		descsize = sizeof (struct nfe_desc32);
1326159952Sobrien	}
1327159952Sobrien
1328159952Sobrien	if (desc != NULL) {
1329159952Sobrien		bus_dmamap_sync(sc->sc_dmat, ring->map, 0,
1330159952Sobrien		    ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1331159952Sobrien		bus_dmamap_unload(sc->sc_dmat, ring->map);
1332159952Sobrien		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)desc,
1333159952Sobrien		    NFE_RX_RING_COUNT * descsize);
1334159952Sobrien		bus_dmamem_free(sc->sc_dmat, &ring->seg, 1);
1335159952Sobrien	}
1336159952Sobrien
1337159952Sobrien	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
1338159952Sobrien		data = &ring->data[i];
1339159952Sobrien
1340159952Sobrien		if (data->map != NULL) {
1341159952Sobrien			bus_dmamap_sync(sc->sc_dmat, data->map, 0,
1342159952Sobrien			    data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1343159952Sobrien			bus_dmamap_unload(sc->sc_dmat, data->map);
1344159952Sobrien			bus_dmamap_destroy(sc->sc_dmat, data->map);
1345159952Sobrien		}
1346159952Sobrien		if (data->m != NULL)
1347159952Sobrien			m_freem(data->m);
1348159952Sobrien	}
1349159952Sobrien}
1350159952Sobrien
1351159952Sobrienstruct nfe_jbuf *
1352159952Sobriennfe_jalloc(struct nfe_softc *sc)
1353159952Sobrien{
1354159952Sobrien	struct nfe_jbuf *jbuf;
1355159952Sobrien
1356159952Sobrien	jbuf = SLIST_FIRST(&sc->rxq.jfreelist);
1357159952Sobrien	if (jbuf == NULL)
1358159952Sobrien		return NULL;
1359159952Sobrien	SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext);
1360159952Sobrien	return jbuf;
1361159952Sobrien}
1362159952Sobrien
1363159952Sobrien/*
1364159952Sobrien * This is called automatically by the network stack when the mbuf is freed.
1365159952Sobrien * Caution must be taken that the NIC might be reset by the time the mbuf is
1366159952Sobrien * freed.
1367159952Sobrien */
1368159952Sobrienvoid
1369159952Sobriennfe_jfree(caddr_t buf, u_int size, void *arg)
1370159952Sobrien{
1371159952Sobrien	struct nfe_softc *sc = arg;
1372159952Sobrien	struct nfe_jbuf *jbuf;
1373159952Sobrien	int i;
1374159952Sobrien
1375159952Sobrien	/* find the jbuf from the base pointer */
1376159952Sobrien	i = (buf - sc->rxq.jpool) / NFE_JBYTES;
1377159952Sobrien	if (i < 0 || i >= NFE_JPOOL_COUNT) {
1378159952Sobrien		printf("%s: request to free a buffer (%p) not managed by us\n",
1379159952Sobrien		    sc->sc_dev.dv_xname, buf);
1380159952Sobrien		return;
1381159952Sobrien	}
1382159952Sobrien	jbuf = &sc->rxq.jbuf[i];
1383159952Sobrien
1384159952Sobrien	/* ..and put it back in the free list */
1385159952Sobrien	SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext);
1386159952Sobrien}
1387159952Sobrien
1388159952Sobrienint
1389159952Sobriennfe_jpool_alloc(struct nfe_softc *sc)
1390159952Sobrien{
1391159952Sobrien	struct nfe_rx_ring *ring = &sc->rxq;
1392159952Sobrien	struct nfe_jbuf *jbuf;
1393159952Sobrien	bus_addr_t physaddr;
1394159952Sobrien	caddr_t buf;
1395159952Sobrien	int i, nsegs, error;
1396159952Sobrien
1397159952Sobrien	/*
1398159952Sobrien	 * Allocate a big chunk of DMA'able memory.
1399159952Sobrien	 */
1400159952Sobrien	error = bus_dmamap_create(sc->sc_dmat, NFE_JPOOL_SIZE, 1,
1401159952Sobrien	    NFE_JPOOL_SIZE, 0, BUS_DMA_NOWAIT, &ring->jmap);
1402159952Sobrien	if (error != 0) {
1403159952Sobrien		printf("%s: could not create jumbo DMA map\n",
1404159952Sobrien		    sc->sc_dev.dv_xname);
1405159952Sobrien		goto fail;
1406159952Sobrien	}
1407159952Sobrien
1408159952Sobrien	error = bus_dmamem_alloc(sc->sc_dmat, NFE_JPOOL_SIZE, PAGE_SIZE, 0,
1409159952Sobrien	    &ring->jseg, 1, &nsegs, BUS_DMA_NOWAIT);
1410159952Sobrien	if (error != 0) {
1411159952Sobrien		printf("%s could not allocate jumbo DMA memory\n",
1412159952Sobrien		    sc->sc_dev.dv_xname);
1413159952Sobrien		goto fail;
1414159952Sobrien	}
1415159952Sobrien
1416159952Sobrien	error = bus_dmamem_map(sc->sc_dmat, &ring->jseg, nsegs, NFE_JPOOL_SIZE,
1417159952Sobrien	    &ring->jpool, BUS_DMA_NOWAIT);
1418159952Sobrien	if (error != 0) {
1419159952Sobrien		printf("%s: could not map jumbo DMA memory\n",
1420159952Sobrien		    sc->sc_dev.dv_xname);
1421159952Sobrien		goto fail;
1422159952Sobrien	}
1423159952Sobrien
1424159952Sobrien	error = bus_dmamap_load(sc->sc_dmat, ring->jmap, ring->jpool,
1425159952Sobrien	    NFE_JPOOL_SIZE, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT);
1426159952Sobrien	if (error != 0) {
1427159952Sobrien		printf("%s: could not load jumbo DMA map\n",
1428159952Sobrien		    sc->sc_dev.dv_xname);
1429159952Sobrien		goto fail;
1430159952Sobrien	}
1431159952Sobrien
1432159952Sobrien	/* ..and split it into 9KB chunks */
1433159952Sobrien	SLIST_INIT(&ring->jfreelist);
1434159952Sobrien
1435159952Sobrien	buf = ring->jpool;
1436159952Sobrien	physaddr = ring->jmap->dm_segs[0].ds_addr;
1437159952Sobrien	for (i = 0; i < NFE_JPOOL_COUNT; i++) {
1438159952Sobrien		jbuf = &ring->jbuf[i];
1439159952Sobrien
1440159952Sobrien		jbuf->buf = buf;
1441159952Sobrien		jbuf->physaddr = physaddr;
1442159952Sobrien
1443159952Sobrien		SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext);
1444159952Sobrien
1445159952Sobrien		buf += NFE_JBYTES;
1446159952Sobrien		physaddr += NFE_JBYTES;
1447159952Sobrien	}
1448159952Sobrien
1449159952Sobrien	return 0;
1450159952Sobrien
1451159952Sobrienfail:	nfe_jpool_free(sc);
1452159952Sobrien	return error;
1453159952Sobrien}
1454159952Sobrien
1455159952Sobrienvoid
1456159952Sobriennfe_jpool_free(struct nfe_softc *sc)
1457159952Sobrien{
1458159952Sobrien	struct nfe_rx_ring *ring = &sc->rxq;
1459159952Sobrien
1460159952Sobrien	if (ring->jmap != NULL) {
1461159952Sobrien		bus_dmamap_sync(sc->sc_dmat, ring->jmap, 0,
1462159952Sobrien		    ring->jmap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1463159952Sobrien		bus_dmamap_unload(sc->sc_dmat, ring->jmap);
1464159952Sobrien		bus_dmamap_destroy(sc->sc_dmat, ring->jmap);
1465159952Sobrien	}
1466159952Sobrien	if (ring->jpool != NULL) {
1467159952Sobrien		bus_dmamem_unmap(sc->sc_dmat, ring->jpool, NFE_JPOOL_SIZE);
1468159952Sobrien		bus_dmamem_free(sc->sc_dmat, &ring->jseg, 1);
1469159952Sobrien	}
1470159952Sobrien}
1471159952Sobrien
1472159952Sobrienint
1473159952Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1474159952Sobrien{
1475159952Sobrien	int i, nsegs, error;
1476159952Sobrien	void **desc;
1477159952Sobrien	int descsize;
1478159952Sobrien
1479159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR) {
1480159952Sobrien		desc = (void **)&ring->desc64;
1481159952Sobrien		descsize = sizeof (struct nfe_desc64);
1482159952Sobrien	} else {
1483159952Sobrien		desc = (void **)&ring->desc32;
1484159952Sobrien		descsize = sizeof (struct nfe_desc32);
1485159952Sobrien	}
1486159952Sobrien
1487159952Sobrien	ring->queued = 0;
1488159952Sobrien	ring->cur = ring->next = 0;
1489159952Sobrien
1490159952Sobrien	error = bus_dmamap_create(sc->sc_dmat, NFE_TX_RING_COUNT * descsize, 1,
1491159952Sobrien	    NFE_TX_RING_COUNT * descsize, 0, BUS_DMA_NOWAIT, &ring->map);
1492159952Sobrien
1493159952Sobrien	if (error != 0) {
1494159952Sobrien		printf("%s: could not create desc DMA map\n",
1495159952Sobrien		    sc->sc_dev.dv_xname);
1496159952Sobrien		goto fail;
1497159952Sobrien	}
1498159952Sobrien
1499159952Sobrien	error = bus_dmamem_alloc(sc->sc_dmat, NFE_TX_RING_COUNT * descsize,
1500159952Sobrien	    PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT);
1501159952Sobrien	if (error != 0) {
1502159952Sobrien		printf("%s: could not allocate DMA memory\n",
1503159952Sobrien		    sc->sc_dev.dv_xname);
1504159952Sobrien		goto fail;
1505159952Sobrien	}
1506159952Sobrien
1507159952Sobrien	error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs,
1508159952Sobrien	    NFE_TX_RING_COUNT * descsize, (caddr_t *)desc, BUS_DMA_NOWAIT);
1509159952Sobrien	if (error != 0) {
1510159952Sobrien		printf("%s: could not map desc DMA memory\n",
1511159952Sobrien		    sc->sc_dev.dv_xname);
1512159952Sobrien		goto fail;
1513159952Sobrien	}
1514159952Sobrien
1515159952Sobrien	error = bus_dmamap_load(sc->sc_dmat, ring->map, *desc,
1516159952Sobrien	    NFE_TX_RING_COUNT * descsize, NULL, BUS_DMA_NOWAIT);
1517159952Sobrien	if (error != 0) {
1518159952Sobrien		printf("%s: could not load desc DMA map\n",
1519159952Sobrien		    sc->sc_dev.dv_xname);
1520159952Sobrien		goto fail;
1521159952Sobrien	}
1522159952Sobrien
1523159952Sobrien	bzero(*desc, NFE_TX_RING_COUNT * descsize);
1524159952Sobrien	ring->physaddr = ring->map->dm_segs[0].ds_addr;
1525159952Sobrien
1526159952Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1527159952Sobrien		error = bus_dmamap_create(sc->sc_dmat, NFE_JBYTES,
1528159952Sobrien		    NFE_MAX_SCATTER, NFE_JBYTES, 0, BUS_DMA_NOWAIT,
1529159952Sobrien		    &ring->data[i].map);
1530159952Sobrien		if (error != 0) {
1531159952Sobrien			printf("%s: could not create DMA map\n",
1532159952Sobrien			    sc->sc_dev.dv_xname);
1533159952Sobrien			goto fail;
1534159952Sobrien		}
1535159952Sobrien	}
1536159952Sobrien
1537159952Sobrien	return 0;
1538159952Sobrien
1539159952Sobrienfail:	nfe_free_tx_ring(sc, ring);
1540159952Sobrien	return error;
1541159952Sobrien}
1542159952Sobrien
1543159952Sobrienvoid
1544159952Sobriennfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1545159952Sobrien{
1546159952Sobrien	struct nfe_tx_data *data;
1547159952Sobrien	int i;
1548159952Sobrien
1549159952Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1550159952Sobrien		if (sc->sc_flags & NFE_40BIT_ADDR)
1551159952Sobrien			ring->desc64[i].flags = 0;
1552159952Sobrien		else
1553159952Sobrien			ring->desc32[i].flags = 0;
1554159952Sobrien
1555159952Sobrien		data = &ring->data[i];
1556159952Sobrien
1557159952Sobrien		if (data->m != NULL) {
1558159952Sobrien			bus_dmamap_sync(sc->sc_dmat, data->active, 0,
1559159952Sobrien			    data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1560159952Sobrien			bus_dmamap_unload(sc->sc_dmat, data->active);
1561159952Sobrien			m_freem(data->m);
1562159952Sobrien			data->m = NULL;
1563159952Sobrien		}
1564159952Sobrien	}
1565159952Sobrien
1566159952Sobrien	bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize,
1567159952Sobrien	    BUS_DMASYNC_PREWRITE);
1568159952Sobrien
1569159952Sobrien	ring->queued = 0;
1570159952Sobrien	ring->cur = ring->next = 0;
1571159952Sobrien}
1572159952Sobrien
1573159952Sobrienvoid
1574159952Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
1575159952Sobrien{
1576159952Sobrien	struct nfe_tx_data *data;
1577159952Sobrien	void *desc;
1578159952Sobrien	int i, descsize;
1579159952Sobrien
1580159952Sobrien	if (sc->sc_flags & NFE_40BIT_ADDR) {
1581159952Sobrien		desc = ring->desc64;
1582159952Sobrien		descsize = sizeof (struct nfe_desc64);
1583159952Sobrien	} else {
1584159952Sobrien		desc = ring->desc32;
1585159952Sobrien		descsize = sizeof (struct nfe_desc32);
1586159952Sobrien	}
1587159952Sobrien
1588159952Sobrien	if (desc != NULL) {
1589159952Sobrien		bus_dmamap_sync(sc->sc_dmat, ring->map, 0,
1590159952Sobrien		    ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1591159952Sobrien		bus_dmamap_unload(sc->sc_dmat, ring->map);
1592159952Sobrien		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)desc,
1593159952Sobrien		    NFE_TX_RING_COUNT * descsize);
1594159952Sobrien		bus_dmamem_free(sc->sc_dmat, &ring->seg, 1);
1595159952Sobrien	}
1596159952Sobrien
1597159952Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1598159952Sobrien		data = &ring->data[i];
1599159952Sobrien
1600159952Sobrien		if (data->m != NULL) {
1601159952Sobrien			bus_dmamap_sync(sc->sc_dmat, data->active, 0,
1602159952Sobrien			    data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1603159952Sobrien			bus_dmamap_unload(sc->sc_dmat, data->active);
1604159952Sobrien			m_freem(data->m);
1605159952Sobrien		}
1606159952Sobrien	}
1607159952Sobrien
1608159952Sobrien	/* ..and now actually destroy the DMA mappings */
1609159952Sobrien	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
1610159952Sobrien		data = &ring->data[i];
1611159952Sobrien		if (data->map == NULL)
1612159952Sobrien			continue;
1613159952Sobrien		bus_dmamap_destroy(sc->sc_dmat, data->map);
1614159952Sobrien	}
1615159952Sobrien}
1616159952Sobrien
1617159952Sobrienint
1618159952Sobriennfe_ifmedia_upd(struct ifnet *ifp)
1619159952Sobrien{
1620159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1621159952Sobrien	struct mii_data *mii = &sc->sc_mii;
1622159952Sobrien	struct mii_softc *miisc;
1623159952Sobrien
1624159952Sobrien	if (mii->mii_instance != 0) {
1625159952Sobrien		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1626159952Sobrien			mii_phy_reset(miisc);
1627159952Sobrien	}
1628159952Sobrien	return mii_mediachg(mii);
1629159952Sobrien}
1630159952Sobrien
1631159952Sobrienvoid
1632159952Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1633159952Sobrien{
1634159952Sobrien	struct nfe_softc *sc = ifp->if_softc;
1635159952Sobrien	struct mii_data *mii = &sc->sc_mii;
1636159952Sobrien
1637159952Sobrien	mii_pollstat(mii);
1638159952Sobrien	ifmr->ifm_status = mii->mii_media_status;
1639159952Sobrien	ifmr->ifm_active = mii->mii_media_active;
1640159952Sobrien}
1641159952Sobrien
1642159952Sobrienvoid
1643159952Sobriennfe_setmulti(struct nfe_softc *sc)
1644159952Sobrien{
1645159952Sobrien	struct arpcom *ac = &sc->sc_arpcom;
1646159952Sobrien	struct ifnet *ifp = &ac->ac_if;
1647159952Sobrien	struct ether_multi *enm;
1648159952Sobrien	struct ether_multistep step;
1649159952Sobrien	uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN];
1650159952Sobrien	uint32_t filter = NFE_RXFILTER_MAGIC;
1651159952Sobrien	int i;
1652159952Sobrien
1653159952Sobrien	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
1654159952Sobrien		bzero(addr, ETHER_ADDR_LEN);
1655159952Sobrien		bzero(mask, ETHER_ADDR_LEN);
1656159952Sobrien		goto done;
1657159952Sobrien	}
1658159952Sobrien
1659159952Sobrien	bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN);
1660159952Sobrien	bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN);
1661159952Sobrien
1662159952Sobrien	ETHER_FIRST_MULTI(step, ac, enm);
1663159952Sobrien	while (enm != NULL) {
1664159952Sobrien		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
1665159952Sobrien			ifp->if_flags |= IFF_ALLMULTI;
1666159952Sobrien			bzero(addr, ETHER_ADDR_LEN);
1667159952Sobrien			bzero(mask, ETHER_ADDR_LEN);
1668159952Sobrien			goto done;
1669159952Sobrien		}
1670159952Sobrien		for (i = 0; i < ETHER_ADDR_LEN; i++) {
1671159952Sobrien			addr[i] &=  enm->enm_addrlo[i];
1672159952Sobrien			mask[i] &= ~enm->enm_addrlo[i];
1673159952Sobrien		}
1674159952Sobrien		ETHER_NEXT_MULTI(step, enm);
1675159952Sobrien	}
1676159952Sobrien	for (i = 0; i < ETHER_ADDR_LEN; i++)
1677159952Sobrien		mask[i] |= addr[i];
1678159952Sobrien
1679159952Sobriendone:
1680159952Sobrien	addr[0] |= 0x01;	/* make sure multicast bit is set */
1681159952Sobrien
1682159952Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_HI,
1683159952Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
1684159952Sobrien	NFE_WRITE(sc, NFE_MULTIADDR_LO,
1685159952Sobrien	    addr[5] <<  8 | addr[4]);
1686159952Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_HI,
1687159952Sobrien	    mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]);
1688159952Sobrien	NFE_WRITE(sc, NFE_MULTIMASK_LO,
1689159952Sobrien	    mask[5] <<  8 | mask[4]);
1690159952Sobrien
1691159952Sobrien	filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M;
1692159952Sobrien	NFE_WRITE(sc, NFE_RXFILTER, filter);
1693159952Sobrien}
1694159952Sobrien
1695159952Sobrienvoid
1696159952Sobriennfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr)
1697159952Sobrien{
1698159952Sobrien	uint32_t tmp;
1699159952Sobrien
1700159952Sobrien	tmp = NFE_READ(sc, NFE_MACADDR_LO);
1701159952Sobrien	addr[0] = (tmp >> 8) & 0xff;
1702159952Sobrien	addr[1] = (tmp & 0xff);
1703159952Sobrien
1704159952Sobrien	tmp = NFE_READ(sc, NFE_MACADDR_HI);
1705159952Sobrien	addr[2] = (tmp >> 24) & 0xff;
1706159952Sobrien	addr[3] = (tmp >> 16) & 0xff;
1707159952Sobrien	addr[4] = (tmp >>  8) & 0xff;
1708159952Sobrien	addr[5] = (tmp & 0xff);
1709159952Sobrien}
1710159952Sobrien
1711159952Sobrienvoid
1712159952Sobriennfe_set_macaddr(struct nfe_softc *sc, const uint8_t *addr)
1713159952Sobrien{
1714159952Sobrien	NFE_WRITE(sc, NFE_MACADDR_LO,
1715159952Sobrien	    addr[5] <<  8 | addr[4]);
1716159952Sobrien	NFE_WRITE(sc, NFE_MACADDR_HI,
1717159952Sobrien	    addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
1718159952Sobrien}
1719159952Sobrien
1720159952Sobrienvoid
1721159952Sobriennfe_tick(void *arg)
1722159952Sobrien{
1723159952Sobrien	struct nfe_softc *sc = arg;
1724159952Sobrien	int s;
1725159952Sobrien
1726159952Sobrien	s = splnet();
1727159952Sobrien	mii_tick(&sc->sc_mii);
1728159952Sobrien	splx(s);
1729159952Sobrien
1730159952Sobrien	timeout_add(&sc->sc_tick_ch, hz);
1731159952Sobrien}
1732