if_arge.c revision 211497
1188808Sgonzo/*-
2188808Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko
3188808Sgonzo * All rights reserved.
4188808Sgonzo *
5188808Sgonzo * Redistribution and use in source and binary forms, with or without
6188808Sgonzo * modification, are permitted provided that the following conditions
7188808Sgonzo * are met:
8188808Sgonzo * 1. Redistributions of source code must retain the above copyright
9188808Sgonzo *    notice unmodified, this list of conditions, and the following
10188808Sgonzo *    disclaimer.
11188808Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
12188808Sgonzo *    notice, this list of conditions and the following disclaimer in the
13188808Sgonzo *    documentation and/or other materials provided with the distribution.
14188808Sgonzo *
15188808Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16188808Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17188808Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18188808Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19188808Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20188808Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21188808Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22188808Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23188808Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24188808Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25188808Sgonzo * SUCH DAMAGE.
26188808Sgonzo */
27188808Sgonzo
28188808Sgonzo#include <sys/cdefs.h>
29188808Sgonzo__FBSDID("$FreeBSD: head/sys/mips/atheros/if_arge.c 211497 2010-08-19 11:16:52Z adrian $");
30188808Sgonzo
31188808Sgonzo/*
32188808Sgonzo * AR71XX gigabit ethernet driver
33188808Sgonzo */
34192783Sgonzo#ifdef HAVE_KERNEL_OPTION_HEADERS
35192783Sgonzo#include "opt_device_polling.h"
36192783Sgonzo#endif
37192783Sgonzo
38188808Sgonzo#include <sys/param.h>
39188808Sgonzo#include <sys/endian.h>
40188808Sgonzo#include <sys/systm.h>
41188808Sgonzo#include <sys/sockio.h>
42188808Sgonzo#include <sys/mbuf.h>
43188808Sgonzo#include <sys/malloc.h>
44188808Sgonzo#include <sys/kernel.h>
45188808Sgonzo#include <sys/module.h>
46188808Sgonzo#include <sys/socket.h>
47188808Sgonzo#include <sys/taskqueue.h>
48209802Sadrian#include <sys/sysctl.h>
49188808Sgonzo
50188808Sgonzo#include <net/if.h>
51188808Sgonzo#include <net/if_arp.h>
52188808Sgonzo#include <net/ethernet.h>
53188808Sgonzo#include <net/if_dl.h>
54188808Sgonzo#include <net/if_media.h>
55188808Sgonzo#include <net/if_types.h>
56188808Sgonzo
57188808Sgonzo#include <net/bpf.h>
58188808Sgonzo
59188808Sgonzo#include <machine/bus.h>
60188808Sgonzo#include <machine/cache.h>
61188808Sgonzo#include <machine/resource.h>
62188808Sgonzo#include <vm/vm_param.h>
63188808Sgonzo#include <vm/vm.h>
64188808Sgonzo#include <vm/pmap.h>
65188808Sgonzo#include <machine/pmap.h>
66188808Sgonzo#include <sys/bus.h>
67188808Sgonzo#include <sys/rman.h>
68188808Sgonzo
69188808Sgonzo#include <dev/mii/mii.h>
70188808Sgonzo#include <dev/mii/miivar.h>
71188808Sgonzo
72188808Sgonzo#include <dev/pci/pcireg.h>
73188808Sgonzo#include <dev/pci/pcivar.h>
74188808Sgonzo
75188808SgonzoMODULE_DEPEND(arge, ether, 1, 1, 1);
76188808SgonzoMODULE_DEPEND(arge, miibus, 1, 1, 1);
77188808Sgonzo
78188808Sgonzo#include "miibus_if.h"
79188808Sgonzo
80188808Sgonzo#include <mips/atheros/ar71xxreg.h>
81188808Sgonzo#include <mips/atheros/if_argevar.h>
82211477Sadrian#include <mips/atheros/ar71xx_cpudef.h>
83188808Sgonzo
84188808Sgonzo#undef ARGE_DEBUG
85188808Sgonzo#ifdef ARGE_DEBUG
86188808Sgonzo#define dprintf printf
87188808Sgonzo#else
88188808Sgonzo#define dprintf(x, arg...)
89188808Sgonzo#endif
90188808Sgonzo
91188808Sgonzostatic int arge_attach(device_t);
92188808Sgonzostatic int arge_detach(device_t);
93188808Sgonzostatic void arge_flush_ddr(struct arge_softc *);
94188808Sgonzostatic int arge_ifmedia_upd(struct ifnet *);
95188808Sgonzostatic void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
96188808Sgonzostatic int arge_ioctl(struct ifnet *, u_long, caddr_t);
97188808Sgonzostatic void arge_init(void *);
98188808Sgonzostatic void arge_init_locked(struct arge_softc *);
99188808Sgonzostatic void arge_link_task(void *, int);
100199234Sgonzostatic void arge_set_pll(struct arge_softc *, int, int);
101188808Sgonzostatic int arge_miibus_readreg(device_t, int, int);
102188808Sgonzostatic void arge_miibus_statchg(device_t);
103188808Sgonzostatic int arge_miibus_writereg(device_t, int, int, int);
104188808Sgonzostatic int arge_probe(device_t);
105188808Sgonzostatic void arge_reset_dma(struct arge_softc *);
106188808Sgonzostatic int arge_resume(device_t);
107188808Sgonzostatic int arge_rx_ring_init(struct arge_softc *);
108188808Sgonzostatic int arge_tx_ring_init(struct arge_softc *);
109192821Sgonzo#ifdef DEVICE_POLLING
110198667Sgonzostatic int arge_poll(struct ifnet *, enum poll_cmd, int);
111192821Sgonzo#endif
112194059Sgonzostatic int arge_shutdown(device_t);
113188808Sgonzostatic void arge_start(struct ifnet *);
114188808Sgonzostatic void arge_start_locked(struct ifnet *);
115188808Sgonzostatic void arge_stop(struct arge_softc *);
116188808Sgonzostatic int arge_suspend(device_t);
117188808Sgonzo
118198667Sgonzostatic int arge_rx_locked(struct arge_softc *);
119188808Sgonzostatic void arge_tx_locked(struct arge_softc *);
120188808Sgonzostatic void arge_intr(void *);
121188808Sgonzostatic int arge_intr_filter(void *);
122188808Sgonzostatic void arge_tick(void *);
123188808Sgonzo
124199234Sgonzo/*
125199234Sgonzo * ifmedia callbacks for multiPHY MAC
126199234Sgonzo */
127199234Sgonzovoid arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *);
128199234Sgonzoint arge_multiphy_mediachange(struct ifnet *);
129199234Sgonzo
130188808Sgonzostatic void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int);
131188808Sgonzostatic int arge_dma_alloc(struct arge_softc *);
132188808Sgonzostatic void arge_dma_free(struct arge_softc *);
133188808Sgonzostatic int arge_newbuf(struct arge_softc *, int);
134188808Sgonzostatic __inline void arge_fixup_rx(struct mbuf *);
135188808Sgonzo
136188808Sgonzostatic device_method_t arge_methods[] = {
137188808Sgonzo	/* Device interface */
138188808Sgonzo	DEVMETHOD(device_probe,		arge_probe),
139188808Sgonzo	DEVMETHOD(device_attach,	arge_attach),
140188808Sgonzo	DEVMETHOD(device_detach,	arge_detach),
141188808Sgonzo	DEVMETHOD(device_suspend,	arge_suspend),
142188808Sgonzo	DEVMETHOD(device_resume,	arge_resume),
143188808Sgonzo	DEVMETHOD(device_shutdown,	arge_shutdown),
144188808Sgonzo
145188808Sgonzo	/* bus interface */
146188808Sgonzo	DEVMETHOD(bus_print_child,	bus_generic_print_child),
147188808Sgonzo	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
148188808Sgonzo
149188808Sgonzo	/* MII interface */
150188808Sgonzo	DEVMETHOD(miibus_readreg,	arge_miibus_readreg),
151188808Sgonzo	DEVMETHOD(miibus_writereg,	arge_miibus_writereg),
152188808Sgonzo	DEVMETHOD(miibus_statchg,	arge_miibus_statchg),
153188808Sgonzo
154188808Sgonzo	{ 0, 0 }
155188808Sgonzo};
156188808Sgonzo
157188808Sgonzostatic driver_t arge_driver = {
158188808Sgonzo	"arge",
159188808Sgonzo	arge_methods,
160188808Sgonzo	sizeof(struct arge_softc)
161188808Sgonzo};
162188808Sgonzo
163188808Sgonzostatic devclass_t arge_devclass;
164188808Sgonzo
165188808SgonzoDRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0);
166188808SgonzoDRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0);
167188808Sgonzo
168188808Sgonzo/*
169192179Sgonzo * RedBoot passes MAC address to entry point as environment
170192179Sgonzo * variable. platfrom_start parses it and stores in this variable
171192179Sgonzo */
172192179Sgonzoextern uint32_t ar711_base_mac[ETHER_ADDR_LEN];
173192179Sgonzo
174199038Sgonzostatic struct mtx miibus_mtx;
175199038Sgonzo
176206400SgonzoMTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF);
177199038Sgonzo
178199038Sgonzo
179192179Sgonzo/*
180188808Sgonzo * Flushes all
181188808Sgonzo */
182188808Sgonzostatic void
183188808Sgonzoarge_flush_ddr(struct arge_softc *sc)
184188808Sgonzo{
185211497Sadrian	if (sc->arge_mac_unit == 0)
186211477Sadrian		ar71xx_device_flush_ddr_ge0();
187211497Sadrian	else
188211477Sadrian		ar71xx_device_flush_ddr_ge1();
189188808Sgonzo}
190188808Sgonzo
191188808Sgonzostatic int
192188808Sgonzoarge_probe(device_t dev)
193188808Sgonzo{
194188808Sgonzo
195188808Sgonzo	device_set_desc(dev, "Atheros AR71xx built-in ethernet interface");
196188808Sgonzo	return (0);
197188808Sgonzo}
198188808Sgonzo
199209802Sadrianstatic void
200209802Sadrianarge_attach_sysctl(device_t dev)
201209802Sadrian{
202209802Sadrian	struct arge_softc *sc = device_get_softc(dev);
203209802Sadrian	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
204209802Sadrian	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
205209802Sadrian
206209802Sadrian	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
207209802Sadrian		"debug", CTLFLAG_RW, &sc->arge_debug, 0,
208209802Sadrian		"arge interface debugging flags");
209209809Sadrian
210209809Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
211209809Sadrian		"tx_pkts_aligned", CTLFLAG_RW, &sc->stats.tx_pkts_aligned, 0,
212209809Sadrian		"number of TX aligned packets");
213209809Sadrian
214209809Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
215209809Sadrian		"tx_pkts_unaligned", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned, 0,
216209809Sadrian		"number of TX unaligned packets");
217209802Sadrian}
218209802Sadrian
219188808Sgonzostatic int
220188808Sgonzoarge_attach(device_t dev)
221188808Sgonzo{
222188808Sgonzo	uint8_t			eaddr[ETHER_ADDR_LEN];
223188808Sgonzo	struct ifnet		*ifp;
224188808Sgonzo	struct arge_softc	*sc;
225199234Sgonzo	int			error = 0, rid, phymask;
226192179Sgonzo	uint32_t		reg, rnd;
227199234Sgonzo	int			is_base_mac_empty, i, phys_total;
228199234Sgonzo	uint32_t		hint;
229188808Sgonzo
230188808Sgonzo	sc = device_get_softc(dev);
231188808Sgonzo	sc->arge_dev = dev;
232188808Sgonzo	sc->arge_mac_unit = device_get_unit(dev);
233188808Sgonzo
234188808Sgonzo	KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)),
235188808Sgonzo	    ("if_arge: Only MAC0 and MAC1 supported"));
236188808Sgonzo	if (sc->arge_mac_unit == 0) {
237188808Sgonzo		sc->arge_pll_reg = AR71XX_PLL_ETH_INT0_CLK;
238198970Sgonzo		sc->arge_pll_reg_shift = 17;
239188808Sgonzo	} else {
240188808Sgonzo		sc->arge_pll_reg = AR71XX_PLL_ETH_INT1_CLK;
241198970Sgonzo		sc->arge_pll_reg_shift = 19;
242188808Sgonzo	}
243188808Sgonzo
244188808Sgonzo	/*
245188808Sgonzo	 *  Get which PHY of 5 available we should use for this unit
246188808Sgonzo	 */
247188808Sgonzo	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
248199234Sgonzo	    "phymask", &phymask) != 0) {
249188808Sgonzo		/*
250188808Sgonzo		 * Use port 4 (WAN) for GE0. For any other port use
251188808Sgonzo		 * its PHY the same as its unit number
252188808Sgonzo		 */
253188808Sgonzo		if (sc->arge_mac_unit == 0)
254199234Sgonzo			phymask = (1 << 4);
255188808Sgonzo		else
256199234Sgonzo			/* Use all phys up to 4 */
257199234Sgonzo			phymask = (1 << 4) - 1;
258188808Sgonzo
259199234Sgonzo		device_printf(dev, "No PHY specified, using mask %d\n", phymask);
260188808Sgonzo	}
261188808Sgonzo
262199234Sgonzo	/*
263199234Sgonzo	 *  Get default media & duplex mode, by default its Base100T
264199234Sgonzo	 *  and full duplex
265199234Sgonzo	 */
266199234Sgonzo	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
267199234Sgonzo	    "media", &hint) != 0)
268199234Sgonzo		hint = 0;
269188808Sgonzo
270199234Sgonzo	if (hint == 1000)
271199234Sgonzo		sc->arge_media_type = IFM_1000_T;
272199234Sgonzo	else
273199234Sgonzo		sc->arge_media_type = IFM_100_TX;
274199234Sgonzo
275199234Sgonzo	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
276199234Sgonzo	    "fduplex", &hint) != 0)
277199234Sgonzo		hint = 1;
278199234Sgonzo
279199234Sgonzo	if (hint)
280199234Sgonzo		sc->arge_duplex_mode = IFM_FDX;
281199234Sgonzo	else
282199234Sgonzo		sc->arge_duplex_mode = 0;
283199234Sgonzo
284199234Sgonzo	sc->arge_phymask = phymask;
285199234Sgonzo
286188808Sgonzo	mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
287188808Sgonzo	    MTX_DEF);
288188808Sgonzo	callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0);
289188808Sgonzo	TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc);
290188808Sgonzo
291188808Sgonzo	/* Map control/status registers. */
292188808Sgonzo	sc->arge_rid = 0;
293188808Sgonzo	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
294188808Sgonzo	    &sc->arge_rid, RF_ACTIVE);
295188808Sgonzo
296188808Sgonzo	if (sc->arge_res == NULL) {
297188808Sgonzo		device_printf(dev, "couldn't map memory\n");
298188808Sgonzo		error = ENXIO;
299188808Sgonzo		goto fail;
300188808Sgonzo	}
301188808Sgonzo
302188808Sgonzo	/* Allocate interrupts */
303188808Sgonzo	rid = 0;
304188808Sgonzo	sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
305188808Sgonzo	    RF_SHAREABLE | RF_ACTIVE);
306188808Sgonzo
307188808Sgonzo	if (sc->arge_irq == NULL) {
308188808Sgonzo		device_printf(dev, "couldn't map interrupt\n");
309188808Sgonzo		error = ENXIO;
310188808Sgonzo		goto fail;
311188808Sgonzo	}
312188808Sgonzo
313188808Sgonzo	/* Allocate ifnet structure. */
314188808Sgonzo	ifp = sc->arge_ifp = if_alloc(IFT_ETHER);
315188808Sgonzo
316188808Sgonzo	if (ifp == NULL) {
317188808Sgonzo		device_printf(dev, "couldn't allocate ifnet structure\n");
318188808Sgonzo		error = ENOSPC;
319188808Sgonzo		goto fail;
320188808Sgonzo	}
321188808Sgonzo
322188808Sgonzo	ifp->if_softc = sc;
323188808Sgonzo	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
324188808Sgonzo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
325188808Sgonzo	ifp->if_ioctl = arge_ioctl;
326188808Sgonzo	ifp->if_start = arge_start;
327188808Sgonzo	ifp->if_init = arge_init;
328198932Sgonzo	sc->arge_if_flags = ifp->if_flags;
329188808Sgonzo
330188808Sgonzo	/* XXX: add real size */
331207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
332207554Ssobomax	ifp->if_snd.ifq_maxlen = ifqmaxlen;
333188808Sgonzo	IFQ_SET_READY(&ifp->if_snd);
334188808Sgonzo
335188808Sgonzo	ifp->if_capenable = ifp->if_capabilities;
336192783Sgonzo#ifdef DEVICE_POLLING
337192783Sgonzo	ifp->if_capabilities |= IFCAP_POLLING;
338192783Sgonzo#endif
339188808Sgonzo
340192179Sgonzo	is_base_mac_empty = 1;
341192179Sgonzo	for (i = 0; i < ETHER_ADDR_LEN; i++) {
342192179Sgonzo		eaddr[i] = ar711_base_mac[i] & 0xff;
343192179Sgonzo		if (eaddr[i] != 0)
344192179Sgonzo			is_base_mac_empty = 0;
345192179Sgonzo	}
346188808Sgonzo
347192179Sgonzo	if (is_base_mac_empty) {
348192179Sgonzo		/*
349192179Sgonzo		 * No MAC address configured. Generate the random one.
350192179Sgonzo		 */
351198933Sgonzo		if  (bootverbose)
352192179Sgonzo			device_printf(dev,
353192179Sgonzo			    "Generating random ethernet address.\n");
354192179Sgonzo
355192179Sgonzo		rnd = arc4random();
356192179Sgonzo		eaddr[0] = 'b';
357192179Sgonzo		eaddr[1] = 's';
358192179Sgonzo		eaddr[2] = 'd';
359192179Sgonzo		eaddr[3] = (rnd >> 24) & 0xff;
360192179Sgonzo		eaddr[4] = (rnd >> 16) & 0xff;
361192179Sgonzo		eaddr[5] = (rnd >> 8) & 0xff;
362192179Sgonzo	}
363192179Sgonzo
364198970Sgonzo	if (sc->arge_mac_unit != 0)
365198970Sgonzo		eaddr[5] +=  sc->arge_mac_unit;
366198970Sgonzo
367188808Sgonzo	if (arge_dma_alloc(sc) != 0) {
368188808Sgonzo		error = ENXIO;
369188808Sgonzo		goto fail;
370188808Sgonzo	}
371188808Sgonzo
372192569Sdwhite	/* Initialize the MAC block */
373192569Sdwhite
374192569Sdwhite	/* Step 1. Soft-reset MAC */
375192569Sdwhite	ARGE_SET_BITS(sc, AR71XX_MAC_CFG1, MAC_CFG1_SOFT_RESET);
376192569Sdwhite	DELAY(20);
377192569Sdwhite
378192569Sdwhite	/* Step 2. Punt the MAC core from the central reset register */
379211477Sadrian	ar71xx_device_stop(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : RST_RESET_GE1_MAC);
380192569Sdwhite	DELAY(100);
381211477Sadrian	ar71xx_device_start(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : RST_RESET_GE1_MAC);
382192569Sdwhite
383192569Sdwhite	/* Step 3. Reconfigure MAC block */
384188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG1,
385188808Sgonzo		MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE |
386188808Sgonzo		MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE);
387188808Sgonzo
388188808Sgonzo	reg = ARGE_READ(sc, AR71XX_MAC_CFG2);
389188808Sgonzo	reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ;
390188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg);
391188808Sgonzo
392188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536);
393188808Sgonzo
394188808Sgonzo	/* Reset MII bus */
395188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET);
396188808Sgonzo	DELAY(100);
397188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28);
398188808Sgonzo	DELAY(100);
399188808Sgonzo
400188808Sgonzo	/*
401188808Sgonzo	 * Set all Ethernet address registers to the same initial values
402188808Sgonzo	 * set all four addresses to 66-88-aa-cc-dd-ee
403188808Sgonzo	 */
404192783Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1,
405192783Sgonzo	    (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8)  | eaddr[5]);
406192783Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (eaddr[0] << 8) | eaddr[1]);
407188808Sgonzo
408188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0,
409188808Sgonzo	    FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT);
410188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000);
411188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff);
412188808Sgonzo
413192783Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH,
414192783Sgonzo	    FIFO_RX_FILTMATCH_DEFAULT);
415188808Sgonzo
416192783Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
417192783Sgonzo	    FIFO_RX_FILTMASK_DEFAULT);
418188808Sgonzo
419199234Sgonzo	/*
420199234Sgonzo	 * Check if we have single-PHY MAC or multi-PHY
421199234Sgonzo	 */
422199234Sgonzo	phys_total = 0;
423199234Sgonzo	for (i = 0; i < ARGE_NPHY; i++)
424199234Sgonzo		if (phymask & (1 << i))
425199234Sgonzo			phys_total ++;
426199234Sgonzo
427199234Sgonzo	if (phys_total == 0) {
428199234Sgonzo		error = EINVAL;
429188808Sgonzo		goto fail;
430188808Sgonzo	}
431188808Sgonzo
432199234Sgonzo	if (phys_total == 1) {
433199234Sgonzo		/* Do MII setup. */
434199234Sgonzo		if (mii_phy_probe(dev, &sc->arge_miibus,
435199234Sgonzo		    arge_ifmedia_upd, arge_ifmedia_sts)) {
436199234Sgonzo			device_printf(dev, "MII without any phy!\n");
437199234Sgonzo			error = ENXIO;
438199234Sgonzo			goto fail;
439199234Sgonzo		}
440199234Sgonzo	}
441199234Sgonzo	else {
442199234Sgonzo		ifmedia_init(&sc->arge_ifmedia, 0,
443199234Sgonzo		    arge_multiphy_mediachange,
444199234Sgonzo		    arge_multiphy_mediastatus);
445199234Sgonzo		ifmedia_add(&sc->arge_ifmedia,
446199234Sgonzo		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode,
447199234Sgonzo		    0, NULL);
448199234Sgonzo		ifmedia_set(&sc->arge_ifmedia,
449199234Sgonzo		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode);
450199234Sgonzo		arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode);
451199234Sgonzo	}
452199234Sgonzo
453188808Sgonzo	/* Call MI attach routine. */
454188808Sgonzo	ether_ifattach(ifp, eaddr);
455188808Sgonzo
456188808Sgonzo	/* Hook interrupt last to avoid having to lock softc */
457188808Sgonzo	error = bus_setup_intr(dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
458188808Sgonzo	    arge_intr_filter, arge_intr, sc, &sc->arge_intrhand);
459188808Sgonzo
460188808Sgonzo	if (error) {
461188808Sgonzo		device_printf(dev, "couldn't set up irq\n");
462188808Sgonzo		ether_ifdetach(ifp);
463188808Sgonzo		goto fail;
464188808Sgonzo	}
465188808Sgonzo
466209802Sadrian	/* setup sysctl variables */
467209802Sadrian	arge_attach_sysctl(dev);
468209802Sadrian
469188808Sgonzofail:
470188808Sgonzo	if (error)
471188808Sgonzo		arge_detach(dev);
472188808Sgonzo
473188808Sgonzo	return (error);
474188808Sgonzo}
475188808Sgonzo
476188808Sgonzostatic int
477188808Sgonzoarge_detach(device_t dev)
478188808Sgonzo{
479192783Sgonzo	struct arge_softc	*sc = device_get_softc(dev);
480188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
481188808Sgonzo
482188808Sgonzo	KASSERT(mtx_initialized(&sc->arge_mtx), ("arge mutex not initialized"));
483188808Sgonzo
484188808Sgonzo	/* These should only be active if attach succeeded */
485188808Sgonzo	if (device_is_attached(dev)) {
486188808Sgonzo		ARGE_LOCK(sc);
487188808Sgonzo		sc->arge_detach = 1;
488192783Sgonzo#ifdef DEVICE_POLLING
489192783Sgonzo		if (ifp->if_capenable & IFCAP_POLLING)
490192783Sgonzo			ether_poll_deregister(ifp);
491192783Sgonzo#endif
492192783Sgonzo
493188808Sgonzo		arge_stop(sc);
494188808Sgonzo		ARGE_UNLOCK(sc);
495188808Sgonzo		taskqueue_drain(taskqueue_swi, &sc->arge_link_task);
496188808Sgonzo		ether_ifdetach(ifp);
497188808Sgonzo	}
498188808Sgonzo
499188808Sgonzo	if (sc->arge_miibus)
500188808Sgonzo		device_delete_child(dev, sc->arge_miibus);
501199234Sgonzo
502188808Sgonzo	bus_generic_detach(dev);
503188808Sgonzo
504188808Sgonzo	if (sc->arge_intrhand)
505188808Sgonzo		bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand);
506188808Sgonzo
507188808Sgonzo	if (sc->arge_res)
508188808Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid,
509188808Sgonzo		    sc->arge_res);
510188808Sgonzo
511188808Sgonzo	if (ifp)
512188808Sgonzo		if_free(ifp);
513188808Sgonzo
514188808Sgonzo	arge_dma_free(sc);
515188808Sgonzo
516188808Sgonzo	mtx_destroy(&sc->arge_mtx);
517188808Sgonzo
518188808Sgonzo	return (0);
519188808Sgonzo
520188808Sgonzo}
521188808Sgonzo
522188808Sgonzostatic int
523188808Sgonzoarge_suspend(device_t dev)
524188808Sgonzo{
525188808Sgonzo
526188808Sgonzo	panic("%s", __func__);
527188808Sgonzo	return 0;
528188808Sgonzo}
529188808Sgonzo
530188808Sgonzostatic int
531188808Sgonzoarge_resume(device_t dev)
532188808Sgonzo{
533188808Sgonzo
534188808Sgonzo	panic("%s", __func__);
535188808Sgonzo	return 0;
536188808Sgonzo}
537188808Sgonzo
538194059Sgonzostatic int
539188808Sgonzoarge_shutdown(device_t dev)
540188808Sgonzo{
541188808Sgonzo	struct arge_softc	*sc;
542188808Sgonzo
543188808Sgonzo	sc = device_get_softc(dev);
544188808Sgonzo
545188808Sgonzo	ARGE_LOCK(sc);
546188808Sgonzo	arge_stop(sc);
547188808Sgonzo	ARGE_UNLOCK(sc);
548194059Sgonzo
549194059Sgonzo	return (0);
550188808Sgonzo}
551188808Sgonzo
552188808Sgonzostatic int
553188808Sgonzoarge_miibus_readreg(device_t dev, int phy, int reg)
554188808Sgonzo{
555188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
556188808Sgonzo	int i, result;
557196794Sgonzo	uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT)
558188808Sgonzo	    | (reg & MAC_MII_REG_MASK);
559188808Sgonzo
560199234Sgonzo	if ((sc->arge_phymask  & (1 << phy)) == 0)
561188808Sgonzo		return (0);
562188808Sgonzo
563199038Sgonzo	mtx_lock(&miibus_mtx);
564199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
565199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr);
566199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
567188808Sgonzo
568188808Sgonzo	i = ARGE_MII_TIMEOUT;
569199038Sgonzo	while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) &
570188808Sgonzo	    MAC_MII_INDICATOR_BUSY) && (i--))
571188808Sgonzo		DELAY(5);
572188808Sgonzo
573188808Sgonzo	if (i < 0) {
574199038Sgonzo		mtx_unlock(&miibus_mtx);
575188808Sgonzo		dprintf("%s timedout\n", __func__);
576188808Sgonzo		/* XXX: return ERRNO istead? */
577188808Sgonzo		return (-1);
578188808Sgonzo	}
579188808Sgonzo
580199038Sgonzo	result = ARGE_MII_READ(AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
581199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
582199038Sgonzo	mtx_unlock(&miibus_mtx);
583199038Sgonzo
584188808Sgonzo	dprintf("%s: phy=%d, reg=%02x, value[%08x]=%04x\n", __func__,
585188808Sgonzo		 phy, reg, addr, result);
586188808Sgonzo
587188808Sgonzo	return (result);
588188808Sgonzo}
589188808Sgonzo
590188808Sgonzostatic int
591188808Sgonzoarge_miibus_writereg(device_t dev, int phy, int reg, int data)
592188808Sgonzo{
593188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
594188808Sgonzo	int i;
595196794Sgonzo	uint32_t addr =
596196794Sgonzo	    (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK);
597188808Sgonzo
598199038Sgonzo
599199234Sgonzo	if ((sc->arge_phymask  & (1 << phy)) == 0)
600199038Sgonzo		return (-1);
601199038Sgonzo
602188808Sgonzo	dprintf("%s: phy=%d, reg=%02x, value=%04x\n", __func__,
603188808Sgonzo	    phy, reg, data);
604188808Sgonzo
605199038Sgonzo	mtx_lock(&miibus_mtx);
606199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr);
607199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CONTROL, data);
608188808Sgonzo
609188808Sgonzo	i = ARGE_MII_TIMEOUT;
610199038Sgonzo	while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) &
611188808Sgonzo	    MAC_MII_INDICATOR_BUSY) && (i--))
612188808Sgonzo		DELAY(5);
613188808Sgonzo
614199038Sgonzo	mtx_unlock(&miibus_mtx);
615199038Sgonzo
616188808Sgonzo	if (i < 0) {
617188808Sgonzo		dprintf("%s timedout\n", __func__);
618188808Sgonzo		/* XXX: return ERRNO istead? */
619188808Sgonzo		return (-1);
620188808Sgonzo	}
621188808Sgonzo
622188808Sgonzo	return (0);
623188808Sgonzo}
624188808Sgonzo
625188808Sgonzostatic void
626188808Sgonzoarge_miibus_statchg(device_t dev)
627188808Sgonzo{
628188808Sgonzo	struct arge_softc		*sc;
629188808Sgonzo
630188808Sgonzo	sc = device_get_softc(dev);
631188808Sgonzo	taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task);
632188808Sgonzo}
633188808Sgonzo
634188808Sgonzostatic void
635188808Sgonzoarge_link_task(void *arg, int pending)
636188808Sgonzo{
637188808Sgonzo	struct arge_softc	*sc;
638188808Sgonzo	struct mii_data		*mii;
639188808Sgonzo	struct ifnet		*ifp;
640199234Sgonzo	uint32_t		media, duplex;
641188808Sgonzo
642188808Sgonzo	sc = (struct arge_softc *)arg;
643188808Sgonzo
644188808Sgonzo	ARGE_LOCK(sc);
645188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
646188808Sgonzo	ifp = sc->arge_ifp;
647188808Sgonzo	if (mii == NULL || ifp == NULL ||
648188808Sgonzo	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
649188808Sgonzo		ARGE_UNLOCK(sc);
650188808Sgonzo		return;
651188808Sgonzo	}
652188808Sgonzo
653188808Sgonzo	if (mii->mii_media_status & IFM_ACTIVE) {
654188808Sgonzo
655188808Sgonzo		media = IFM_SUBTYPE(mii->mii_media_active);
656188808Sgonzo
657188808Sgonzo		if (media != IFM_NONE) {
658188808Sgonzo			sc->arge_link_status = 1;
659199234Sgonzo			duplex = mii->mii_media_active & IFM_GMASK;
660199234Sgonzo			arge_set_pll(sc, media, duplex);
661199234Sgonzo		}
662199234Sgonzo	} else
663199234Sgonzo		sc->arge_link_status = 0;
664188808Sgonzo
665199234Sgonzo	ARGE_UNLOCK(sc);
666199234Sgonzo}
667192783Sgonzo
668199234Sgonzostatic void
669199234Sgonzoarge_set_pll(struct arge_softc *sc, int media, int duplex)
670199234Sgonzo{
671199234Sgonzo	uint32_t		cfg, ifcontrol, rx_filtmask, pll, sec_cfg;
672192783Sgonzo
673199234Sgonzo	cfg = ARGE_READ(sc, AR71XX_MAC_CFG2);
674199234Sgonzo	cfg &= ~(MAC_CFG2_IFACE_MODE_1000
675199234Sgonzo	    | MAC_CFG2_IFACE_MODE_10_100
676199234Sgonzo	    | MAC_CFG2_FULL_DUPLEX);
677188808Sgonzo
678199234Sgonzo	if (duplex == IFM_FDX)
679199234Sgonzo		cfg |= MAC_CFG2_FULL_DUPLEX;
680188808Sgonzo
681199234Sgonzo	ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL);
682199234Sgonzo	ifcontrol &= ~MAC_IFCONTROL_SPEED;
683199234Sgonzo	rx_filtmask =
684199234Sgonzo	    ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK);
685199234Sgonzo	rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE;
686188808Sgonzo
687199234Sgonzo	switch(media) {
688199234Sgonzo	case IFM_10_T:
689199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
690199234Sgonzo		pll = PLL_ETH_INT_CLK_10;
691199234Sgonzo		break;
692199234Sgonzo	case IFM_100_TX:
693199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
694199234Sgonzo		ifcontrol |= MAC_IFCONTROL_SPEED;
695199234Sgonzo		pll = PLL_ETH_INT_CLK_100;
696199234Sgonzo		break;
697199234Sgonzo	case IFM_1000_T:
698199234Sgonzo	case IFM_1000_SX:
699199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_1000;
700199234Sgonzo		rx_filtmask |= FIFO_RX_MASK_BYTE_MODE;
701199234Sgonzo		pll = PLL_ETH_INT_CLK_1000;
702199234Sgonzo		break;
703199234Sgonzo	default:
704199234Sgonzo		pll = PLL_ETH_INT_CLK_100;
705199234Sgonzo		device_printf(sc->arge_dev,
706199234Sgonzo		    "Unknown media %d\n", media);
707199234Sgonzo	}
708188808Sgonzo
709199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD,
710199234Sgonzo	    0x008001ff);
711188808Sgonzo
712199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg);
713199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol);
714199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
715199234Sgonzo	    rx_filtmask);
716188808Sgonzo
717199234Sgonzo	/* set PLL registers */
718199234Sgonzo	sec_cfg = ATH_READ_REG(AR71XX_PLL_SEC_CONFIG);
719199234Sgonzo	sec_cfg &= ~(3 << sc->arge_pll_reg_shift);
720199234Sgonzo	sec_cfg |= (2 << sc->arge_pll_reg_shift);
721188808Sgonzo
722199234Sgonzo	ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg);
723199234Sgonzo	DELAY(100);
724188808Sgonzo
725199234Sgonzo	ATH_WRITE_REG(sc->arge_pll_reg, pll);
726188808Sgonzo
727199234Sgonzo	sec_cfg |= (3 << sc->arge_pll_reg_shift);
728199234Sgonzo	ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg);
729199234Sgonzo	DELAY(100);
730199234Sgonzo
731199234Sgonzo	sec_cfg &= ~(3 << sc->arge_pll_reg_shift);
732199234Sgonzo	ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg);
733199234Sgonzo	DELAY(100);
734188808Sgonzo}
735188808Sgonzo
736199234Sgonzo
737188808Sgonzostatic void
738188808Sgonzoarge_reset_dma(struct arge_softc *sc)
739188808Sgonzo{
740188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0);
741188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0);
742188808Sgonzo
743188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0);
744188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0);
745188808Sgonzo
746188808Sgonzo	/* Clear all possible RX interrupts */
747192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD)
748188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
749188808Sgonzo
750188808Sgonzo	/*
751188808Sgonzo	 * Clear all possible TX interrupts
752188808Sgonzo	 */
753192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT)
754188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
755188808Sgonzo
756188808Sgonzo	/*
757188808Sgonzo	 * Now Rx/Tx errors
758188808Sgonzo	 */
759188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS,
760188808Sgonzo	    DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW);
761188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS,
762188808Sgonzo	    DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN);
763188808Sgonzo}
764188808Sgonzo
765188808Sgonzo
766188808Sgonzo
767188808Sgonzostatic void
768188808Sgonzoarge_init(void *xsc)
769188808Sgonzo{
770188808Sgonzo	struct arge_softc	 *sc = xsc;
771188808Sgonzo
772188808Sgonzo	ARGE_LOCK(sc);
773188808Sgonzo	arge_init_locked(sc);
774188808Sgonzo	ARGE_UNLOCK(sc);
775188808Sgonzo}
776188808Sgonzo
777188808Sgonzostatic void
778188808Sgonzoarge_init_locked(struct arge_softc *sc)
779188808Sgonzo{
780188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
781188808Sgonzo	struct mii_data		*mii;
782188808Sgonzo
783188808Sgonzo	ARGE_LOCK_ASSERT(sc);
784188808Sgonzo
785188808Sgonzo	arge_stop(sc);
786188808Sgonzo
787188808Sgonzo	/* Init circular RX list. */
788188808Sgonzo	if (arge_rx_ring_init(sc) != 0) {
789188808Sgonzo		device_printf(sc->arge_dev,
790188808Sgonzo		    "initialization failed: no memory for rx buffers\n");
791188808Sgonzo		arge_stop(sc);
792188808Sgonzo		return;
793188808Sgonzo	}
794188808Sgonzo
795188808Sgonzo	/* Init tx descriptors. */
796188808Sgonzo	arge_tx_ring_init(sc);
797188808Sgonzo
798188808Sgonzo	arge_reset_dma(sc);
799188808Sgonzo
800188808Sgonzo
801199234Sgonzo	if (sc->arge_miibus) {
802199234Sgonzo		sc->arge_link_status = 0;
803199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
804199234Sgonzo		mii_mediachg(mii);
805199234Sgonzo	}
806199234Sgonzo	else {
807199234Sgonzo		/*
808199234Sgonzo		 * Sun always shines over multiPHY interface
809199234Sgonzo		 */
810199234Sgonzo		sc->arge_link_status = 1;
811199234Sgonzo	}
812199234Sgonzo
813188808Sgonzo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
814188808Sgonzo	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
815188808Sgonzo
816199234Sgonzo	if (sc->arge_miibus)
817199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
818192783Sgonzo
819188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0));
820188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0));
821188808Sgonzo
822188808Sgonzo	/* Start listening */
823188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
824188808Sgonzo
825188808Sgonzo	/* Enable interrupts */
826188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
827188808Sgonzo}
828188808Sgonzo
829188808Sgonzo/*
830209807Sadrian * Return whether the mbuf chain is correctly aligned
831209807Sadrian * for the arge TX engine.
832209807Sadrian *
833209807Sadrian * The TX engine requires each fragment to be aligned to a
834209807Sadrian * 4 byte boundary and the size of each fragment except
835209807Sadrian * the last to be a multiple of 4 bytes.
836209807Sadrian */
837209807Sadrianstatic int
838209807Sadrianarge_mbuf_chain_is_tx_aligned(struct mbuf *m0)
839209807Sadrian{
840209807Sadrian	struct mbuf *m;
841209807Sadrian
842209807Sadrian	for (m = m0; m != NULL; m = m->m_next) {
843209807Sadrian		if((mtod(m, intptr_t) & 3) != 0)
844209807Sadrian			return 0;
845209807Sadrian		if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0))
846209807Sadrian			return 0;
847209807Sadrian	}
848209807Sadrian	return 1;
849209807Sadrian}
850209807Sadrian
851209807Sadrian/*
852188808Sgonzo * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
853188808Sgonzo * pointers to the fragment pointers.
854188808Sgonzo */
855188808Sgonzostatic int
856188808Sgonzoarge_encap(struct arge_softc *sc, struct mbuf **m_head)
857188808Sgonzo{
858188808Sgonzo	struct arge_txdesc	*txd;
859188808Sgonzo	struct arge_desc	*desc, *prev_desc;
860188808Sgonzo	bus_dma_segment_t	txsegs[ARGE_MAXFRAGS];
861192569Sdwhite	int			error, i, nsegs, prod, prev_prod;
862192783Sgonzo	struct mbuf		*m;
863188808Sgonzo
864188808Sgonzo	ARGE_LOCK_ASSERT(sc);
865188808Sgonzo
866192783Sgonzo	/*
867192783Sgonzo	 * Fix mbuf chain, all fragments should be 4 bytes aligned and
868192783Sgonzo	 * even 4 bytes
869192783Sgonzo	 */
870192783Sgonzo	m = *m_head;
871209807Sadrian	if (! arge_mbuf_chain_is_tx_aligned(m)) {
872209809Sadrian		sc->stats.tx_pkts_unaligned++;
873192783Sgonzo		m = m_defrag(*m_head, M_DONTWAIT);
874192783Sgonzo		if (m == NULL) {
875192783Sgonzo			*m_head = NULL;
876192783Sgonzo			return (ENOBUFS);
877192783Sgonzo		}
878192783Sgonzo		*m_head = m;
879209809Sadrian	} else
880209809Sadrian		sc->stats.tx_pkts_aligned++;
881192783Sgonzo
882188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
883188808Sgonzo	txd = &sc->arge_cdata.arge_txdesc[prod];
884188808Sgonzo	error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag,
885188808Sgonzo	    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
886188808Sgonzo
887188808Sgonzo	if (error == EFBIG) {
888188808Sgonzo		panic("EFBIG");
889188808Sgonzo	} else if (error != 0)
890188808Sgonzo		return (error);
891188808Sgonzo
892188808Sgonzo	if (nsegs == 0) {
893188808Sgonzo		m_freem(*m_head);
894188808Sgonzo		*m_head = NULL;
895188808Sgonzo		return (EIO);
896188808Sgonzo	}
897188808Sgonzo
898188808Sgonzo	/* Check number of available descriptors. */
899188808Sgonzo	if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 1)) {
900188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
901188808Sgonzo		return (ENOBUFS);
902188808Sgonzo	}
903188808Sgonzo
904188808Sgonzo	txd->tx_m = *m_head;
905188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
906188808Sgonzo	    BUS_DMASYNC_PREWRITE);
907188808Sgonzo
908188808Sgonzo	/*
909188808Sgonzo	 * Make a list of descriptors for this packet. DMA controller will
910188808Sgonzo	 * walk through it while arge_link is not zero.
911188808Sgonzo	 */
912188808Sgonzo	prev_prod = prod;
913188808Sgonzo	desc = prev_desc = NULL;
914188808Sgonzo	for (i = 0; i < nsegs; i++) {
915188808Sgonzo		desc = &sc->arge_rdata.arge_tx_ring[prod];
916188808Sgonzo		desc->packet_ctrl = ARGE_DMASIZE(txsegs[i].ds_len);
917188808Sgonzo
918192783Sgonzo		if (txsegs[i].ds_addr & 3)
919192783Sgonzo			panic("TX packet address unaligned\n");
920192783Sgonzo
921188808Sgonzo		desc->packet_addr = txsegs[i].ds_addr;
922192783Sgonzo
923188808Sgonzo		/* link with previous descriptor */
924188808Sgonzo		if (prev_desc)
925188808Sgonzo			prev_desc->packet_ctrl |= ARGE_DESC_MORE;
926188808Sgonzo
927188808Sgonzo		sc->arge_cdata.arge_tx_cnt++;
928188808Sgonzo		prev_desc = desc;
929188808Sgonzo		ARGE_INC(prod, ARGE_TX_RING_COUNT);
930188808Sgonzo	}
931188808Sgonzo
932188808Sgonzo	/* Update producer index. */
933188808Sgonzo	sc->arge_cdata.arge_tx_prod = prod;
934188808Sgonzo
935188808Sgonzo	/* Sync descriptors. */
936188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
937188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
938188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
939188808Sgonzo
940188808Sgonzo	/* Start transmitting */
941188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN);
942188808Sgonzo	return (0);
943188808Sgonzo}
944188808Sgonzo
945188808Sgonzostatic void
946188808Sgonzoarge_start(struct ifnet *ifp)
947188808Sgonzo{
948188808Sgonzo	struct arge_softc	 *sc;
949188808Sgonzo
950188808Sgonzo	sc = ifp->if_softc;
951188808Sgonzo
952188808Sgonzo	ARGE_LOCK(sc);
953188808Sgonzo	arge_start_locked(ifp);
954188808Sgonzo	ARGE_UNLOCK(sc);
955188808Sgonzo}
956188808Sgonzo
957188808Sgonzostatic void
958188808Sgonzoarge_start_locked(struct ifnet *ifp)
959188808Sgonzo{
960188808Sgonzo	struct arge_softc	*sc;
961188808Sgonzo	struct mbuf		*m_head;
962188808Sgonzo	int			enq;
963188808Sgonzo
964188808Sgonzo	sc = ifp->if_softc;
965188808Sgonzo
966188808Sgonzo	ARGE_LOCK_ASSERT(sc);
967188808Sgonzo
968188808Sgonzo	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
969188808Sgonzo	    IFF_DRV_RUNNING || sc->arge_link_status == 0 )
970188808Sgonzo		return;
971188808Sgonzo
972188808Sgonzo	arge_flush_ddr(sc);
973188808Sgonzo
974188808Sgonzo	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
975188808Sgonzo	    sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) {
976188808Sgonzo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
977188808Sgonzo		if (m_head == NULL)
978188808Sgonzo			break;
979188808Sgonzo
980188808Sgonzo
981188808Sgonzo		/*
982188808Sgonzo		 * Pack the data into the transmit ring.
983188808Sgonzo		 */
984188808Sgonzo		if (arge_encap(sc, &m_head)) {
985188808Sgonzo			if (m_head == NULL)
986188808Sgonzo				break;
987188808Sgonzo			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
988188808Sgonzo			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
989188808Sgonzo			break;
990188808Sgonzo		}
991188808Sgonzo
992188808Sgonzo		enq++;
993188808Sgonzo		/*
994188808Sgonzo		 * If there's a BPF listener, bounce a copy of this frame
995188808Sgonzo		 * to him.
996188808Sgonzo		 */
997188808Sgonzo		ETHER_BPF_MTAP(ifp, m_head);
998188808Sgonzo	}
999188808Sgonzo}
1000188808Sgonzo
1001188808Sgonzostatic void
1002188808Sgonzoarge_stop(struct arge_softc *sc)
1003188808Sgonzo{
1004188808Sgonzo	struct ifnet	    *ifp;
1005188808Sgonzo
1006188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1007188808Sgonzo
1008188808Sgonzo	ifp = sc->arge_ifp;
1009188808Sgonzo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1010199234Sgonzo	if (sc->arge_miibus)
1011199234Sgonzo		callout_stop(&sc->arge_stat_callout);
1012188808Sgonzo
1013188808Sgonzo	/* mask out interrupts */
1014188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1015188808Sgonzo
1016188808Sgonzo	arge_reset_dma(sc);
1017188808Sgonzo}
1018188808Sgonzo
1019188808Sgonzo
1020188808Sgonzostatic int
1021188808Sgonzoarge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1022188808Sgonzo{
1023188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1024188808Sgonzo	struct ifreq		*ifr = (struct ifreq *) data;
1025188808Sgonzo	struct mii_data		*mii;
1026188808Sgonzo	int			error;
1027192783Sgonzo#ifdef DEVICE_POLLING
1028192783Sgonzo	int			mask;
1029192783Sgonzo#endif
1030188808Sgonzo
1031188808Sgonzo	switch (command) {
1032188808Sgonzo	case SIOCSIFFLAGS:
1033198932Sgonzo		ARGE_LOCK(sc);
1034198932Sgonzo		if ((ifp->if_flags & IFF_UP) != 0) {
1035198932Sgonzo			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1036198932Sgonzo				if (((ifp->if_flags ^ sc->arge_if_flags)
1037198939Sgonzo				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0) {
1038198939Sgonzo					/* XXX: handle promisc & multi flags */
1039198939Sgonzo				}
1040198939Sgonzo
1041198932Sgonzo			} else {
1042198932Sgonzo				if (!sc->arge_detach)
1043198932Sgonzo					arge_init_locked(sc);
1044198932Sgonzo			}
1045198932Sgonzo		} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1046198932Sgonzo			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1047198932Sgonzo			arge_stop(sc);
1048198932Sgonzo		}
1049198932Sgonzo		sc->arge_if_flags = ifp->if_flags;
1050198932Sgonzo		ARGE_UNLOCK(sc);
1051188808Sgonzo		error = 0;
1052188808Sgonzo		break;
1053188808Sgonzo	case SIOCADDMULTI:
1054188808Sgonzo	case SIOCDELMULTI:
1055198932Sgonzo		/* XXX: implement SIOCDELMULTI */
1056188808Sgonzo		error = 0;
1057188808Sgonzo		break;
1058188808Sgonzo	case SIOCGIFMEDIA:
1059188808Sgonzo	case SIOCSIFMEDIA:
1060199234Sgonzo		if (sc->arge_miibus) {
1061199234Sgonzo			mii = device_get_softc(sc->arge_miibus);
1062199234Sgonzo			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
1063199234Sgonzo		}
1064199234Sgonzo		else
1065199234Sgonzo			error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia, command);
1066188808Sgonzo		break;
1067198933Sgonzo	case SIOCSIFCAP:
1068198932Sgonzo		/* XXX: Check other capabilities */
1069192783Sgonzo#ifdef DEVICE_POLLING
1070198933Sgonzo		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
1071198933Sgonzo		if (mask & IFCAP_POLLING) {
1072198933Sgonzo			if (ifr->ifr_reqcap & IFCAP_POLLING) {
1073192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1074198933Sgonzo				error = ether_poll_register(arge_poll, ifp);
1075198933Sgonzo				if (error)
1076198933Sgonzo					return error;
1077198933Sgonzo				ARGE_LOCK(sc);
1078198933Sgonzo				ifp->if_capenable |= IFCAP_POLLING;
1079198933Sgonzo				ARGE_UNLOCK(sc);
1080198933Sgonzo			} else {
1081192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1082198933Sgonzo				error = ether_poll_deregister(ifp);
1083198933Sgonzo				ARGE_LOCK(sc);
1084198933Sgonzo				ifp->if_capenable &= ~IFCAP_POLLING;
1085198933Sgonzo				ARGE_UNLOCK(sc);
1086198933Sgonzo			}
1087198933Sgonzo		}
1088198932Sgonzo		error = 0;
1089198933Sgonzo		break;
1090192783Sgonzo#endif
1091188808Sgonzo	default:
1092188808Sgonzo		error = ether_ioctl(ifp, command, data);
1093188808Sgonzo		break;
1094188808Sgonzo	}
1095188808Sgonzo
1096188808Sgonzo	return (error);
1097188808Sgonzo}
1098188808Sgonzo
1099188808Sgonzo/*
1100188808Sgonzo * Set media options.
1101188808Sgonzo */
1102188808Sgonzostatic int
1103188808Sgonzoarge_ifmedia_upd(struct ifnet *ifp)
1104188808Sgonzo{
1105188808Sgonzo	struct arge_softc		*sc;
1106188808Sgonzo	struct mii_data		*mii;
1107188808Sgonzo	struct mii_softc	*miisc;
1108188808Sgonzo	int			error;
1109188808Sgonzo
1110188808Sgonzo	sc = ifp->if_softc;
1111188808Sgonzo	ARGE_LOCK(sc);
1112188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1113188808Sgonzo	if (mii->mii_instance) {
1114188808Sgonzo		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1115188808Sgonzo			mii_phy_reset(miisc);
1116188808Sgonzo	}
1117188808Sgonzo	error = mii_mediachg(mii);
1118188808Sgonzo	ARGE_UNLOCK(sc);
1119188808Sgonzo
1120188808Sgonzo	return (error);
1121188808Sgonzo}
1122188808Sgonzo
1123188808Sgonzo/*
1124188808Sgonzo * Report current media status.
1125188808Sgonzo */
1126188808Sgonzostatic void
1127188808Sgonzoarge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1128188808Sgonzo{
1129188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1130188808Sgonzo	struct mii_data		*mii;
1131188808Sgonzo
1132188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1133188808Sgonzo	ARGE_LOCK(sc);
1134188808Sgonzo	mii_pollstat(mii);
1135188808Sgonzo	ARGE_UNLOCK(sc);
1136188808Sgonzo	ifmr->ifm_active = mii->mii_media_active;
1137188808Sgonzo	ifmr->ifm_status = mii->mii_media_status;
1138188808Sgonzo}
1139188808Sgonzo
1140188808Sgonzostruct arge_dmamap_arg {
1141188808Sgonzo	bus_addr_t	arge_busaddr;
1142188808Sgonzo};
1143188808Sgonzo
1144188808Sgonzostatic void
1145188808Sgonzoarge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1146188808Sgonzo{
1147188808Sgonzo	struct arge_dmamap_arg	*ctx;
1148188808Sgonzo
1149188808Sgonzo	if (error != 0)
1150188808Sgonzo		return;
1151188808Sgonzo	ctx = arg;
1152188808Sgonzo	ctx->arge_busaddr = segs[0].ds_addr;
1153188808Sgonzo}
1154188808Sgonzo
1155188808Sgonzostatic int
1156188808Sgonzoarge_dma_alloc(struct arge_softc *sc)
1157188808Sgonzo{
1158188808Sgonzo	struct arge_dmamap_arg	ctx;
1159188808Sgonzo	struct arge_txdesc	*txd;
1160188808Sgonzo	struct arge_rxdesc	*rxd;
1161188808Sgonzo	int			error, i;
1162188808Sgonzo
1163188808Sgonzo	/* Create parent DMA tag. */
1164188808Sgonzo	error = bus_dma_tag_create(
1165188808Sgonzo	    bus_get_dma_tag(sc->arge_dev),	/* parent */
1166188808Sgonzo	    1, 0,			/* alignment, boundary */
1167188808Sgonzo	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1168188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1169188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1170188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
1171188808Sgonzo	    0,				/* nsegments */
1172188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1173188808Sgonzo	    0,				/* flags */
1174188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1175188808Sgonzo	    &sc->arge_cdata.arge_parent_tag);
1176188808Sgonzo	if (error != 0) {
1177188808Sgonzo		device_printf(sc->arge_dev, "failed to create parent DMA tag\n");
1178188808Sgonzo		goto fail;
1179188808Sgonzo	}
1180188808Sgonzo	/* Create tag for Tx ring. */
1181188808Sgonzo	error = bus_dma_tag_create(
1182188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1183188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1184188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1185188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1186188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1187188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsize */
1188188808Sgonzo	    1,				/* nsegments */
1189188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsegsize */
1190188808Sgonzo	    0,				/* flags */
1191188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1192188808Sgonzo	    &sc->arge_cdata.arge_tx_ring_tag);
1193188808Sgonzo	if (error != 0) {
1194188808Sgonzo		device_printf(sc->arge_dev, "failed to create Tx ring DMA tag\n");
1195188808Sgonzo		goto fail;
1196188808Sgonzo	}
1197188808Sgonzo
1198188808Sgonzo	/* Create tag for Rx ring. */
1199188808Sgonzo	error = bus_dma_tag_create(
1200188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1201188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1202188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1203188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1204188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1205188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsize */
1206188808Sgonzo	    1,				/* nsegments */
1207188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsegsize */
1208188808Sgonzo	    0,				/* flags */
1209188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1210188808Sgonzo	    &sc->arge_cdata.arge_rx_ring_tag);
1211188808Sgonzo	if (error != 0) {
1212188808Sgonzo		device_printf(sc->arge_dev, "failed to create Rx ring DMA tag\n");
1213188808Sgonzo		goto fail;
1214188808Sgonzo	}
1215188808Sgonzo
1216188808Sgonzo	/* Create tag for Tx buffers. */
1217188808Sgonzo	error = bus_dma_tag_create(
1218188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1219188808Sgonzo	    sizeof(uint32_t), 0,	/* alignment, boundary */
1220188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1221188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1222188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1223188808Sgonzo	    MCLBYTES * ARGE_MAXFRAGS,	/* maxsize */
1224188808Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1225188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1226188808Sgonzo	    0,				/* flags */
1227188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1228188808Sgonzo	    &sc->arge_cdata.arge_tx_tag);
1229188808Sgonzo	if (error != 0) {
1230188808Sgonzo		device_printf(sc->arge_dev, "failed to create Tx DMA tag\n");
1231188808Sgonzo		goto fail;
1232188808Sgonzo	}
1233188808Sgonzo
1234188808Sgonzo	/* Create tag for Rx buffers. */
1235188808Sgonzo	error = bus_dma_tag_create(
1236188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1237188808Sgonzo	    ARGE_RX_ALIGN, 0,		/* alignment, boundary */
1238188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1239188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1240188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1241188808Sgonzo	    MCLBYTES,			/* maxsize */
1242192821Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1243188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1244188808Sgonzo	    0,				/* flags */
1245188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1246188808Sgonzo	    &sc->arge_cdata.arge_rx_tag);
1247188808Sgonzo	if (error != 0) {
1248188808Sgonzo		device_printf(sc->arge_dev, "failed to create Rx DMA tag\n");
1249188808Sgonzo		goto fail;
1250188808Sgonzo	}
1251188808Sgonzo
1252188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
1253188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag,
1254188808Sgonzo	    (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK |
1255188808Sgonzo	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_tx_ring_map);
1256188808Sgonzo	if (error != 0) {
1257188808Sgonzo		device_printf(sc->arge_dev,
1258188808Sgonzo		    "failed to allocate DMA'able memory for Tx ring\n");
1259188808Sgonzo		goto fail;
1260188808Sgonzo	}
1261188808Sgonzo
1262188808Sgonzo	ctx.arge_busaddr = 0;
1263188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag,
1264188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring,
1265188808Sgonzo	    ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1266188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1267188808Sgonzo		device_printf(sc->arge_dev,
1268188808Sgonzo		    "failed to load DMA'able memory for Tx ring\n");
1269188808Sgonzo		goto fail;
1270188808Sgonzo	}
1271188808Sgonzo	sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr;
1272188808Sgonzo
1273188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
1274188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag,
1275188808Sgonzo	    (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK |
1276188808Sgonzo	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_rx_ring_map);
1277188808Sgonzo	if (error != 0) {
1278188808Sgonzo		device_printf(sc->arge_dev,
1279188808Sgonzo		    "failed to allocate DMA'able memory for Rx ring\n");
1280188808Sgonzo		goto fail;
1281188808Sgonzo	}
1282188808Sgonzo
1283188808Sgonzo	ctx.arge_busaddr = 0;
1284188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag,
1285188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring,
1286188808Sgonzo	    ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1287188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1288188808Sgonzo		device_printf(sc->arge_dev,
1289188808Sgonzo		    "failed to load DMA'able memory for Rx ring\n");
1290188808Sgonzo		goto fail;
1291188808Sgonzo	}
1292188808Sgonzo	sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr;
1293188808Sgonzo
1294188808Sgonzo	/* Create DMA maps for Tx buffers. */
1295188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1296188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
1297188808Sgonzo		txd->tx_m = NULL;
1298188808Sgonzo		txd->tx_dmamap = NULL;
1299188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0,
1300188808Sgonzo		    &txd->tx_dmamap);
1301188808Sgonzo		if (error != 0) {
1302188808Sgonzo			device_printf(sc->arge_dev,
1303188808Sgonzo			    "failed to create Tx dmamap\n");
1304188808Sgonzo			goto fail;
1305188808Sgonzo		}
1306188808Sgonzo	}
1307188808Sgonzo	/* Create DMA maps for Rx buffers. */
1308188808Sgonzo	if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
1309188808Sgonzo	    &sc->arge_cdata.arge_rx_sparemap)) != 0) {
1310188808Sgonzo		device_printf(sc->arge_dev,
1311188808Sgonzo		    "failed to create spare Rx dmamap\n");
1312188808Sgonzo		goto fail;
1313188808Sgonzo	}
1314188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1315188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
1316188808Sgonzo		rxd->rx_m = NULL;
1317188808Sgonzo		rxd->rx_dmamap = NULL;
1318188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
1319188808Sgonzo		    &rxd->rx_dmamap);
1320188808Sgonzo		if (error != 0) {
1321188808Sgonzo			device_printf(sc->arge_dev,
1322188808Sgonzo			    "failed to create Rx dmamap\n");
1323188808Sgonzo			goto fail;
1324188808Sgonzo		}
1325188808Sgonzo	}
1326188808Sgonzo
1327188808Sgonzofail:
1328188808Sgonzo	return (error);
1329188808Sgonzo}
1330188808Sgonzo
1331188808Sgonzostatic void
1332188808Sgonzoarge_dma_free(struct arge_softc *sc)
1333188808Sgonzo{
1334188808Sgonzo	struct arge_txdesc	*txd;
1335188808Sgonzo	struct arge_rxdesc	*rxd;
1336188808Sgonzo	int			i;
1337188808Sgonzo
1338188808Sgonzo	/* Tx ring. */
1339188808Sgonzo	if (sc->arge_cdata.arge_tx_ring_tag) {
1340188808Sgonzo		if (sc->arge_cdata.arge_tx_ring_map)
1341188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag,
1342188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
1343188808Sgonzo		if (sc->arge_cdata.arge_tx_ring_map &&
1344188808Sgonzo		    sc->arge_rdata.arge_tx_ring)
1345188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag,
1346188808Sgonzo			    sc->arge_rdata.arge_tx_ring,
1347188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
1348188808Sgonzo		sc->arge_rdata.arge_tx_ring = NULL;
1349188808Sgonzo		sc->arge_cdata.arge_tx_ring_map = NULL;
1350188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag);
1351188808Sgonzo		sc->arge_cdata.arge_tx_ring_tag = NULL;
1352188808Sgonzo	}
1353188808Sgonzo	/* Rx ring. */
1354188808Sgonzo	if (sc->arge_cdata.arge_rx_ring_tag) {
1355188808Sgonzo		if (sc->arge_cdata.arge_rx_ring_map)
1356188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag,
1357188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
1358188808Sgonzo		if (sc->arge_cdata.arge_rx_ring_map &&
1359188808Sgonzo		    sc->arge_rdata.arge_rx_ring)
1360188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag,
1361188808Sgonzo			    sc->arge_rdata.arge_rx_ring,
1362188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
1363188808Sgonzo		sc->arge_rdata.arge_rx_ring = NULL;
1364188808Sgonzo		sc->arge_cdata.arge_rx_ring_map = NULL;
1365188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag);
1366188808Sgonzo		sc->arge_cdata.arge_rx_ring_tag = NULL;
1367188808Sgonzo	}
1368188808Sgonzo	/* Tx buffers. */
1369188808Sgonzo	if (sc->arge_cdata.arge_tx_tag) {
1370188808Sgonzo		for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1371188808Sgonzo			txd = &sc->arge_cdata.arge_txdesc[i];
1372188808Sgonzo			if (txd->tx_dmamap) {
1373188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag,
1374188808Sgonzo				    txd->tx_dmamap);
1375188808Sgonzo				txd->tx_dmamap = NULL;
1376188808Sgonzo			}
1377188808Sgonzo		}
1378188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag);
1379188808Sgonzo		sc->arge_cdata.arge_tx_tag = NULL;
1380188808Sgonzo	}
1381188808Sgonzo	/* Rx buffers. */
1382188808Sgonzo	if (sc->arge_cdata.arge_rx_tag) {
1383188808Sgonzo		for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1384188808Sgonzo			rxd = &sc->arge_cdata.arge_rxdesc[i];
1385188808Sgonzo			if (rxd->rx_dmamap) {
1386188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
1387188808Sgonzo				    rxd->rx_dmamap);
1388188808Sgonzo				rxd->rx_dmamap = NULL;
1389188808Sgonzo			}
1390188808Sgonzo		}
1391188808Sgonzo		if (sc->arge_cdata.arge_rx_sparemap) {
1392188808Sgonzo			bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
1393188808Sgonzo			    sc->arge_cdata.arge_rx_sparemap);
1394188808Sgonzo			sc->arge_cdata.arge_rx_sparemap = 0;
1395188808Sgonzo		}
1396188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag);
1397188808Sgonzo		sc->arge_cdata.arge_rx_tag = NULL;
1398188808Sgonzo	}
1399188808Sgonzo
1400188808Sgonzo	if (sc->arge_cdata.arge_parent_tag) {
1401188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag);
1402188808Sgonzo		sc->arge_cdata.arge_parent_tag = NULL;
1403188808Sgonzo	}
1404188808Sgonzo}
1405188808Sgonzo
1406188808Sgonzo/*
1407188808Sgonzo * Initialize the transmit descriptors.
1408188808Sgonzo */
1409188808Sgonzostatic int
1410188808Sgonzoarge_tx_ring_init(struct arge_softc *sc)
1411188808Sgonzo{
1412188808Sgonzo	struct arge_ring_data	*rd;
1413188808Sgonzo	struct arge_txdesc	*txd;
1414188808Sgonzo	bus_addr_t		addr;
1415188808Sgonzo	int			i;
1416188808Sgonzo
1417188808Sgonzo	sc->arge_cdata.arge_tx_prod = 0;
1418188808Sgonzo	sc->arge_cdata.arge_tx_cons = 0;
1419188808Sgonzo	sc->arge_cdata.arge_tx_cnt = 0;
1420188808Sgonzo	sc->arge_cdata.arge_tx_pkts = 0;
1421188808Sgonzo
1422188808Sgonzo	rd = &sc->arge_rdata;
1423188808Sgonzo	bzero(rd->arge_tx_ring, sizeof(rd->arge_tx_ring));
1424188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1425188808Sgonzo		if (i == ARGE_TX_RING_COUNT - 1)
1426188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, 0);
1427188808Sgonzo		else
1428188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, i + 1);
1429188808Sgonzo		rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY;
1430188808Sgonzo		rd->arge_tx_ring[i].next_desc = addr;
1431188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
1432188808Sgonzo		txd->tx_m = NULL;
1433188808Sgonzo	}
1434188808Sgonzo
1435188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1436188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1437188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1438188808Sgonzo
1439188808Sgonzo	return (0);
1440188808Sgonzo}
1441188808Sgonzo
1442188808Sgonzo/*
1443188808Sgonzo * Initialize the RX descriptors and allocate mbufs for them. Note that
1444188808Sgonzo * we arrange the descriptors in a closed ring, so that the last descriptor
1445188808Sgonzo * points back to the first.
1446188808Sgonzo */
1447188808Sgonzostatic int
1448188808Sgonzoarge_rx_ring_init(struct arge_softc *sc)
1449188808Sgonzo{
1450188808Sgonzo	struct arge_ring_data	*rd;
1451188808Sgonzo	struct arge_rxdesc	*rxd;
1452188808Sgonzo	bus_addr_t		addr;
1453188808Sgonzo	int			i;
1454188808Sgonzo
1455188808Sgonzo	sc->arge_cdata.arge_rx_cons = 0;
1456188808Sgonzo
1457188808Sgonzo	rd = &sc->arge_rdata;
1458188808Sgonzo	bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring));
1459188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1460188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
1461188808Sgonzo		rxd->rx_m = NULL;
1462188808Sgonzo		rxd->desc = &rd->arge_rx_ring[i];
1463188808Sgonzo		if (i == ARGE_RX_RING_COUNT - 1)
1464188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, 0);
1465188808Sgonzo		else
1466188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, i + 1);
1467188808Sgonzo		rd->arge_rx_ring[i].next_desc = addr;
1468192783Sgonzo		if (arge_newbuf(sc, i) != 0) {
1469188808Sgonzo			return (ENOBUFS);
1470192783Sgonzo		}
1471188808Sgonzo	}
1472188808Sgonzo
1473188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1474188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
1475195434Sgonzo	    BUS_DMASYNC_PREWRITE);
1476188808Sgonzo
1477188808Sgonzo	return (0);
1478188808Sgonzo}
1479188808Sgonzo
1480188808Sgonzo/*
1481188808Sgonzo * Initialize an RX descriptor and attach an MBUF cluster.
1482188808Sgonzo */
1483188808Sgonzostatic int
1484188808Sgonzoarge_newbuf(struct arge_softc *sc, int idx)
1485188808Sgonzo{
1486188808Sgonzo	struct arge_desc		*desc;
1487188808Sgonzo	struct arge_rxdesc	*rxd;
1488188808Sgonzo	struct mbuf		*m;
1489188808Sgonzo	bus_dma_segment_t	segs[1];
1490188808Sgonzo	bus_dmamap_t		map;
1491188808Sgonzo	int			nsegs;
1492188808Sgonzo
1493188808Sgonzo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1494188808Sgonzo	if (m == NULL)
1495188808Sgonzo		return (ENOBUFS);
1496188808Sgonzo	m->m_len = m->m_pkthdr.len = MCLBYTES;
1497188808Sgonzo	m_adj(m, sizeof(uint64_t));
1498188808Sgonzo
1499188808Sgonzo	if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag,
1500188808Sgonzo	    sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) {
1501188808Sgonzo		m_freem(m);
1502188808Sgonzo		return (ENOBUFS);
1503188808Sgonzo	}
1504188808Sgonzo	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1505188808Sgonzo
1506188808Sgonzo	rxd = &sc->arge_cdata.arge_rxdesc[idx];
1507188808Sgonzo	if (rxd->rx_m != NULL) {
1508188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap);
1509188808Sgonzo	}
1510188808Sgonzo	map = rxd->rx_dmamap;
1511188808Sgonzo	rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap;
1512188808Sgonzo	sc->arge_cdata.arge_rx_sparemap = map;
1513188808Sgonzo	rxd->rx_m = m;
1514188808Sgonzo	desc = rxd->desc;
1515192783Sgonzo	if (segs[0].ds_addr & 3)
1516192783Sgonzo		panic("RX packet address unaligned");
1517188808Sgonzo	desc->packet_addr = segs[0].ds_addr;
1518192783Sgonzo	desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len);
1519188808Sgonzo
1520195434Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1521195434Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
1522195434Sgonzo	    BUS_DMASYNC_PREWRITE);
1523195434Sgonzo
1524188808Sgonzo	return (0);
1525188808Sgonzo}
1526188808Sgonzo
1527188808Sgonzostatic __inline void
1528188808Sgonzoarge_fixup_rx(struct mbuf *m)
1529188808Sgonzo{
1530198933Sgonzo	int		i;
1531198933Sgonzo	uint16_t	*src, *dst;
1532188808Sgonzo
1533188808Sgonzo	src = mtod(m, uint16_t *);
1534188808Sgonzo	dst = src - 1;
1535188808Sgonzo
1536195434Sgonzo	for (i = 0; i < m->m_len / sizeof(uint16_t); i++) {
1537188808Sgonzo		*dst++ = *src++;
1538195434Sgonzo	}
1539188808Sgonzo
1540195434Sgonzo	if (m->m_len % sizeof(uint16_t))
1541195434Sgonzo		*(uint8_t *)dst = *(uint8_t *)src;
1542195434Sgonzo
1543188808Sgonzo	m->m_data -= ETHER_ALIGN;
1544188808Sgonzo}
1545188808Sgonzo
1546192783Sgonzo#ifdef DEVICE_POLLING
1547198667Sgonzostatic int
1548192783Sgonzoarge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1549192783Sgonzo{
1550192783Sgonzo	struct arge_softc *sc = ifp->if_softc;
1551198667Sgonzo	int rx_npkts = 0;
1552188808Sgonzo
1553198933Sgonzo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1554192783Sgonzo		ARGE_LOCK(sc);
1555192783Sgonzo		arge_tx_locked(sc);
1556198667Sgonzo		rx_npkts = arge_rx_locked(sc);
1557192783Sgonzo		ARGE_UNLOCK(sc);
1558198933Sgonzo	}
1559198667Sgonzo
1560198667Sgonzo	return (rx_npkts);
1561192783Sgonzo}
1562192783Sgonzo#endif /* DEVICE_POLLING */
1563192783Sgonzo
1564192783Sgonzo
1565188808Sgonzostatic void
1566188808Sgonzoarge_tx_locked(struct arge_softc *sc)
1567188808Sgonzo{
1568188808Sgonzo	struct arge_txdesc	*txd;
1569188808Sgonzo	struct arge_desc	*cur_tx;
1570188808Sgonzo	struct ifnet		*ifp;
1571188808Sgonzo	uint32_t		ctrl;
1572188808Sgonzo	int			cons, prod;
1573188808Sgonzo
1574188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1575188808Sgonzo
1576188808Sgonzo	cons = sc->arge_cdata.arge_tx_cons;
1577188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
1578188808Sgonzo	if (cons == prod)
1579188808Sgonzo		return;
1580188808Sgonzo
1581188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1582188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1583188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1584188808Sgonzo
1585188808Sgonzo	ifp = sc->arge_ifp;
1586188808Sgonzo	/*
1587188808Sgonzo	 * Go through our tx list and free mbufs for those
1588188808Sgonzo	 * frames that have been transmitted.
1589188808Sgonzo	 */
1590188808Sgonzo	for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) {
1591188808Sgonzo		cur_tx = &sc->arge_rdata.arge_tx_ring[cons];
1592188808Sgonzo		ctrl = cur_tx->packet_ctrl;
1593188808Sgonzo		/* Check if descriptor has "finished" flag */
1594188808Sgonzo		if ((ctrl & ARGE_DESC_EMPTY) == 0)
1595188808Sgonzo			break;
1596188808Sgonzo
1597188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
1598188808Sgonzo
1599188808Sgonzo		sc->arge_cdata.arge_tx_cnt--;
1600188808Sgonzo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1601188808Sgonzo
1602188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[cons];
1603188808Sgonzo
1604188808Sgonzo		ifp->if_opackets++;
1605188808Sgonzo
1606188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
1607188808Sgonzo		    BUS_DMASYNC_POSTWRITE);
1608188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
1609188808Sgonzo
1610188808Sgonzo		/* Free only if it's first descriptor in list */
1611188808Sgonzo		if (txd->tx_m)
1612188808Sgonzo			m_freem(txd->tx_m);
1613188808Sgonzo		txd->tx_m = NULL;
1614188808Sgonzo
1615188808Sgonzo		/* reset descriptor */
1616188808Sgonzo		cur_tx->packet_addr = 0;
1617188808Sgonzo	}
1618188808Sgonzo
1619188808Sgonzo	sc->arge_cdata.arge_tx_cons = cons;
1620188808Sgonzo
1621188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1622188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE);
1623188808Sgonzo}
1624188808Sgonzo
1625188808Sgonzo
1626198667Sgonzostatic int
1627188808Sgonzoarge_rx_locked(struct arge_softc *sc)
1628188808Sgonzo{
1629188808Sgonzo	struct arge_rxdesc	*rxd;
1630188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
1631192783Sgonzo	int			cons, prog, packet_len, i;
1632188808Sgonzo	struct arge_desc	*cur_rx;
1633188808Sgonzo	struct mbuf		*m;
1634198667Sgonzo	int			rx_npkts = 0;
1635188808Sgonzo
1636188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1637188808Sgonzo
1638188808Sgonzo	cons = sc->arge_cdata.arge_rx_cons;
1639188808Sgonzo
1640188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1641188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
1642188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1643188808Sgonzo
1644188808Sgonzo	for (prog = 0; prog < ARGE_RX_RING_COUNT;
1645188808Sgonzo	    ARGE_INC(cons, ARGE_RX_RING_COUNT)) {
1646188808Sgonzo		cur_rx = &sc->arge_rdata.arge_rx_ring[cons];
1647188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[cons];
1648188808Sgonzo		m = rxd->rx_m;
1649188808Sgonzo
1650188808Sgonzo		if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0)
1651188808Sgonzo		       break;
1652188808Sgonzo
1653188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
1654188808Sgonzo
1655188808Sgonzo		prog++;
1656188808Sgonzo
1657188808Sgonzo		packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl);
1658188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
1659195434Sgonzo		    BUS_DMASYNC_POSTREAD);
1660188808Sgonzo		m = rxd->rx_m;
1661188808Sgonzo
1662188808Sgonzo		arge_fixup_rx(m);
1663188808Sgonzo		m->m_pkthdr.rcvif = ifp;
1664188808Sgonzo		/* Skip 4 bytes of CRC */
1665188808Sgonzo		m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
1666188808Sgonzo		ifp->if_ipackets++;
1667198667Sgonzo		rx_npkts++;
1668188808Sgonzo
1669188808Sgonzo		ARGE_UNLOCK(sc);
1670188808Sgonzo		(*ifp->if_input)(ifp, m);
1671188808Sgonzo		ARGE_LOCK(sc);
1672192783Sgonzo		cur_rx->packet_addr = 0;
1673192783Sgonzo	}
1674188808Sgonzo
1675192783Sgonzo	if (prog > 0) {
1676192783Sgonzo
1677192783Sgonzo		i = sc->arge_cdata.arge_rx_cons;
1678192783Sgonzo		for (; prog > 0 ; prog--) {
1679192783Sgonzo			if (arge_newbuf(sc, i) != 0) {
1680192783Sgonzo				device_printf(sc->arge_dev,
1681192783Sgonzo				    "Failed to allocate buffer\n");
1682192783Sgonzo				break;
1683192783Sgonzo			}
1684192783Sgonzo			ARGE_INC(i, ARGE_RX_RING_COUNT);
1685188808Sgonzo		}
1686188808Sgonzo
1687188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1688188808Sgonzo		    sc->arge_cdata.arge_rx_ring_map,
1689195434Sgonzo		    BUS_DMASYNC_PREWRITE);
1690188808Sgonzo
1691188808Sgonzo		sc->arge_cdata.arge_rx_cons = cons;
1692188808Sgonzo	}
1693198667Sgonzo
1694198667Sgonzo	return (rx_npkts);
1695188808Sgonzo}
1696188808Sgonzo
1697188808Sgonzostatic int
1698188808Sgonzoarge_intr_filter(void *arg)
1699188808Sgonzo{
1700188808Sgonzo	struct arge_softc	*sc = arg;
1701188808Sgonzo	uint32_t		status, ints;
1702188808Sgonzo
1703188808Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
1704188808Sgonzo	ints = ARGE_READ(sc, AR71XX_DMA_INTR);
1705188808Sgonzo
1706188808Sgonzo#if 0
1707188808Sgonzo	dprintf("int mask(filter) = %b\n", ints,
1708188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
1709188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
1710188808Sgonzo	dprintf("status(filter) = %b\n", status,
1711188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
1712188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
1713188808Sgonzo#endif
1714188808Sgonzo
1715188808Sgonzo	if (status & DMA_INTR_ALL) {
1716191644Sgonzo		sc->arge_intr_status |= status;
1717192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1718188808Sgonzo		return (FILTER_SCHEDULE_THREAD);
1719192783Sgonzo	}
1720188808Sgonzo
1721188808Sgonzo	sc->arge_intr_status = 0;
1722188808Sgonzo	return (FILTER_STRAY);
1723188808Sgonzo}
1724188808Sgonzo
1725188808Sgonzostatic void
1726188808Sgonzoarge_intr(void *arg)
1727188808Sgonzo{
1728188808Sgonzo	struct arge_softc	*sc = arg;
1729188808Sgonzo	uint32_t		status;
1730188808Sgonzo
1731192783Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
1732192783Sgonzo	status |= sc->arge_intr_status;
1733188808Sgonzo
1734188808Sgonzo#if 0
1735188808Sgonzo	dprintf("int status(intr) = %b\n", status,
1736188808Sgonzo	    "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD"
1737188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
1738188808Sgonzo#endif
1739188808Sgonzo
1740188808Sgonzo	/*
1741188808Sgonzo	 * Is it our interrupt at all?
1742188808Sgonzo	 */
1743188808Sgonzo	if (status == 0)
1744188808Sgonzo		return;
1745188808Sgonzo
1746188808Sgonzo	if (status & DMA_INTR_RX_BUS_ERROR) {
1747188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR);
1748188808Sgonzo		device_printf(sc->arge_dev, "RX bus error");
1749188808Sgonzo		return;
1750188808Sgonzo	}
1751188808Sgonzo
1752188808Sgonzo	if (status & DMA_INTR_TX_BUS_ERROR) {
1753188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR);
1754188808Sgonzo		device_printf(sc->arge_dev, "TX bus error");
1755188808Sgonzo		return;
1756188808Sgonzo	}
1757188808Sgonzo
1758192783Sgonzo	ARGE_LOCK(sc);
1759188808Sgonzo
1760192783Sgonzo	if (status & DMA_INTR_RX_PKT_RCVD)
1761192783Sgonzo		arge_rx_locked(sc);
1762188808Sgonzo
1763192783Sgonzo	/*
1764192783Sgonzo	 * RX overrun disables the receiver.
1765192783Sgonzo	 * Clear indication and re-enable rx.
1766192783Sgonzo	 */
1767192783Sgonzo	if ( status & DMA_INTR_RX_OVERFLOW) {
1768192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW);
1769192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
1770192783Sgonzo	}
1771188808Sgonzo
1772192783Sgonzo	if (status & DMA_INTR_TX_PKT_SENT)
1773192783Sgonzo		arge_tx_locked(sc);
1774192783Sgonzo	/*
1775192783Sgonzo	 * Underrun turns off TX. Clear underrun indication.
1776192783Sgonzo	 * If there's anything left in the ring, reactivate the tx.
1777192783Sgonzo	 */
1778192569Sdwhite	if (status & DMA_INTR_TX_UNDERRUN) {
1779192569Sdwhite		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN);
1780192783Sgonzo		if (sc->arge_cdata.arge_tx_pkts > 0 ) {
1781192783Sgonzo			ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL,
1782192783Sgonzo			    DMA_TX_CONTROL_EN);
1783192783Sgonzo		}
1784192569Sdwhite	}
1785192569Sdwhite
1786192946Sgonzo	/*
1787192946Sgonzo	 * We handled all bits, clear status
1788192946Sgonzo	 */
1789192946Sgonzo	sc->arge_intr_status = 0;
1790188808Sgonzo	ARGE_UNLOCK(sc);
1791192783Sgonzo	/*
1792192783Sgonzo	 * re-enable all interrupts
1793192783Sgonzo	 */
1794192783Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1795188808Sgonzo}
1796188808Sgonzo
1797192783Sgonzo
1798188808Sgonzostatic void
1799188808Sgonzoarge_tick(void *xsc)
1800188808Sgonzo{
1801188808Sgonzo	struct arge_softc	*sc = xsc;
1802188808Sgonzo	struct mii_data		*mii;
1803188808Sgonzo
1804188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1805188808Sgonzo
1806199234Sgonzo	if (sc->arge_miibus) {
1807199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
1808199234Sgonzo		mii_tick(mii);
1809199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
1810199234Sgonzo	}
1811188808Sgonzo}
1812199234Sgonzo
1813199234Sgonzoint
1814199234Sgonzoarge_multiphy_mediachange(struct ifnet *ifp)
1815199234Sgonzo{
1816199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
1817199234Sgonzo	struct ifmedia *ifm = &sc->arge_ifmedia;
1818199234Sgonzo	struct ifmedia_entry *ife = ifm->ifm_cur;
1819199234Sgonzo
1820199234Sgonzo	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1821199234Sgonzo		return (EINVAL);
1822199234Sgonzo
1823199234Sgonzo	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
1824199234Sgonzo		device_printf(sc->arge_dev,
1825199234Sgonzo		    "AUTO is not supported for multiphy MAC");
1826199234Sgonzo		return (EINVAL);
1827199234Sgonzo	}
1828199234Sgonzo
1829199234Sgonzo	/*
1830199234Sgonzo	 * Ignore everything
1831199234Sgonzo	 */
1832199234Sgonzo	return (0);
1833199234Sgonzo}
1834199234Sgonzo
1835199234Sgonzovoid
1836199234Sgonzoarge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1837199234Sgonzo{
1838199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
1839199234Sgonzo
1840199234Sgonzo	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1841199234Sgonzo	ifmr->ifm_active = IFM_ETHER | sc->arge_media_type |
1842199234Sgonzo	    sc->arge_duplex_mode;
1843199234Sgonzo}
1844199234Sgonzo
1845