if_arge.c revision 234859
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 234859 2012-05-01 04:35:53Z adrian $");
30188808Sgonzo
31188808Sgonzo/*
32188808Sgonzo * AR71XX gigabit ethernet driver
33188808Sgonzo */
34192783Sgonzo#ifdef HAVE_KERNEL_OPTION_HEADERS
35192783Sgonzo#include "opt_device_polling.h"
36192783Sgonzo#endif
37192783Sgonzo
38234859Sadrian#include "opt_arge.h"
39234859Sadrian
40188808Sgonzo#include <sys/param.h>
41188808Sgonzo#include <sys/endian.h>
42188808Sgonzo#include <sys/systm.h>
43188808Sgonzo#include <sys/sockio.h>
44188808Sgonzo#include <sys/mbuf.h>
45188808Sgonzo#include <sys/malloc.h>
46188808Sgonzo#include <sys/kernel.h>
47188808Sgonzo#include <sys/module.h>
48188808Sgonzo#include <sys/socket.h>
49188808Sgonzo#include <sys/taskqueue.h>
50209802Sadrian#include <sys/sysctl.h>
51188808Sgonzo
52188808Sgonzo#include <net/if.h>
53188808Sgonzo#include <net/if_arp.h>
54188808Sgonzo#include <net/ethernet.h>
55188808Sgonzo#include <net/if_dl.h>
56188808Sgonzo#include <net/if_media.h>
57188808Sgonzo#include <net/if_types.h>
58188808Sgonzo
59188808Sgonzo#include <net/bpf.h>
60188808Sgonzo
61188808Sgonzo#include <machine/bus.h>
62188808Sgonzo#include <machine/cache.h>
63188808Sgonzo#include <machine/resource.h>
64188808Sgonzo#include <vm/vm_param.h>
65188808Sgonzo#include <vm/vm.h>
66188808Sgonzo#include <vm/pmap.h>
67188808Sgonzo#include <machine/pmap.h>
68188808Sgonzo#include <sys/bus.h>
69188808Sgonzo#include <sys/rman.h>
70188808Sgonzo
71188808Sgonzo#include <dev/mii/mii.h>
72188808Sgonzo#include <dev/mii/miivar.h>
73188808Sgonzo
74188808Sgonzo#include <dev/pci/pcireg.h>
75188808Sgonzo#include <dev/pci/pcivar.h>
76188808Sgonzo
77188808SgonzoMODULE_DEPEND(arge, ether, 1, 1, 1);
78188808SgonzoMODULE_DEPEND(arge, miibus, 1, 1, 1);
79188808Sgonzo
80188808Sgonzo#include "miibus_if.h"
81188808Sgonzo
82188808Sgonzo#include <mips/atheros/ar71xxreg.h>
83188808Sgonzo#include <mips/atheros/if_argevar.h>
84219589Sadrian#include <mips/atheros/ar71xx_setup.h>
85211477Sadrian#include <mips/atheros/ar71xx_cpudef.h>
86188808Sgonzo
87220354Sadriantypedef enum {
88220354Sadrian	ARGE_DBG_MII 	=	0x00000001,
89220356Sadrian	ARGE_DBG_INTR	=	0x00000002,
90220356Sadrian	ARGE_DBG_TX	=	0x00000004,
91220356Sadrian	ARGE_DBG_RX	=	0x00000008,
92220356Sadrian	ARGE_DBG_ERR	=	0x00000010,
93220356Sadrian	ARGE_DBG_RESET	=	0x00000020,
94220354Sadrian} arge_debug_flags;
95220354Sadrian
96188808Sgonzo#ifdef ARGE_DEBUG
97220354Sadrian#define	ARGEDEBUG(_sc, _m, ...) 					\
98220354Sadrian	do {								\
99220354Sadrian		if ((_m) & (_sc)->arge_debug)				\
100220354Sadrian			device_printf((_sc)->arge_dev, __VA_ARGS__);	\
101220354Sadrian	} while (0)
102188808Sgonzo#else
103220354Sadrian#define	ARGEDEBUG(_sc, _m, ...)
104188808Sgonzo#endif
105188808Sgonzo
106188808Sgonzostatic int arge_attach(device_t);
107188808Sgonzostatic int arge_detach(device_t);
108188808Sgonzostatic void arge_flush_ddr(struct arge_softc *);
109188808Sgonzostatic int arge_ifmedia_upd(struct ifnet *);
110188808Sgonzostatic void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
111188808Sgonzostatic int arge_ioctl(struct ifnet *, u_long, caddr_t);
112188808Sgonzostatic void arge_init(void *);
113188808Sgonzostatic void arge_init_locked(struct arge_softc *);
114188808Sgonzostatic void arge_link_task(void *, int);
115232914Sadrianstatic void arge_update_link_locked(struct arge_softc *sc);
116199234Sgonzostatic void arge_set_pll(struct arge_softc *, int, int);
117188808Sgonzostatic int arge_miibus_readreg(device_t, int, int);
118188808Sgonzostatic void arge_miibus_statchg(device_t);
119188808Sgonzostatic int arge_miibus_writereg(device_t, int, int, int);
120188808Sgonzostatic int arge_probe(device_t);
121188808Sgonzostatic void arge_reset_dma(struct arge_softc *);
122188808Sgonzostatic int arge_resume(device_t);
123188808Sgonzostatic int arge_rx_ring_init(struct arge_softc *);
124232912Sadrianstatic void arge_rx_ring_free(struct arge_softc *sc);
125188808Sgonzostatic int arge_tx_ring_init(struct arge_softc *);
126192821Sgonzo#ifdef DEVICE_POLLING
127198667Sgonzostatic int arge_poll(struct ifnet *, enum poll_cmd, int);
128192821Sgonzo#endif
129194059Sgonzostatic int arge_shutdown(device_t);
130188808Sgonzostatic void arge_start(struct ifnet *);
131188808Sgonzostatic void arge_start_locked(struct ifnet *);
132188808Sgonzostatic void arge_stop(struct arge_softc *);
133188808Sgonzostatic int arge_suspend(device_t);
134188808Sgonzo
135198667Sgonzostatic int arge_rx_locked(struct arge_softc *);
136188808Sgonzostatic void arge_tx_locked(struct arge_softc *);
137188808Sgonzostatic void arge_intr(void *);
138188808Sgonzostatic int arge_intr_filter(void *);
139188808Sgonzostatic void arge_tick(void *);
140188808Sgonzo
141199234Sgonzo/*
142199234Sgonzo * ifmedia callbacks for multiPHY MAC
143199234Sgonzo */
144199234Sgonzovoid arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *);
145199234Sgonzoint arge_multiphy_mediachange(struct ifnet *);
146199234Sgonzo
147188808Sgonzostatic void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int);
148188808Sgonzostatic int arge_dma_alloc(struct arge_softc *);
149188808Sgonzostatic void arge_dma_free(struct arge_softc *);
150188808Sgonzostatic int arge_newbuf(struct arge_softc *, int);
151188808Sgonzostatic __inline void arge_fixup_rx(struct mbuf *);
152188808Sgonzo
153188808Sgonzostatic device_method_t arge_methods[] = {
154188808Sgonzo	/* Device interface */
155188808Sgonzo	DEVMETHOD(device_probe,		arge_probe),
156188808Sgonzo	DEVMETHOD(device_attach,	arge_attach),
157188808Sgonzo	DEVMETHOD(device_detach,	arge_detach),
158188808Sgonzo	DEVMETHOD(device_suspend,	arge_suspend),
159188808Sgonzo	DEVMETHOD(device_resume,	arge_resume),
160188808Sgonzo	DEVMETHOD(device_shutdown,	arge_shutdown),
161188808Sgonzo
162188808Sgonzo	/* MII interface */
163188808Sgonzo	DEVMETHOD(miibus_readreg,	arge_miibus_readreg),
164188808Sgonzo	DEVMETHOD(miibus_writereg,	arge_miibus_writereg),
165188808Sgonzo	DEVMETHOD(miibus_statchg,	arge_miibus_statchg),
166188808Sgonzo
167227843Smarius	DEVMETHOD_END
168188808Sgonzo};
169188808Sgonzo
170188808Sgonzostatic driver_t arge_driver = {
171188808Sgonzo	"arge",
172188808Sgonzo	arge_methods,
173188808Sgonzo	sizeof(struct arge_softc)
174188808Sgonzo};
175188808Sgonzo
176188808Sgonzostatic devclass_t arge_devclass;
177188808Sgonzo
178188808SgonzoDRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0);
179188808SgonzoDRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0);
180188808Sgonzo
181188808Sgonzo/*
182232627Sray * RedBoot passes MAC address to entry point as environment
183192179Sgonzo * variable. platfrom_start parses it and stores in this variable
184192179Sgonzo */
185192179Sgonzoextern uint32_t ar711_base_mac[ETHER_ADDR_LEN];
186192179Sgonzo
187199038Sgonzostatic struct mtx miibus_mtx;
188199038Sgonzo
189206400SgonzoMTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF);
190199038Sgonzo
191192179Sgonzo/*
192232627Sray * Flushes all
193188808Sgonzo */
194188808Sgonzostatic void
195188808Sgonzoarge_flush_ddr(struct arge_softc *sc)
196188808Sgonzo{
197228064Sray
198228064Sray	ar71xx_device_flush_ddr_ge(sc->arge_mac_unit);
199188808Sgonzo}
200188808Sgonzo
201232627Sraystatic int
202188808Sgonzoarge_probe(device_t dev)
203188808Sgonzo{
204188808Sgonzo
205188808Sgonzo	device_set_desc(dev, "Atheros AR71xx built-in ethernet interface");
206188808Sgonzo	return (0);
207188808Sgonzo}
208188808Sgonzo
209209802Sadrianstatic void
210209802Sadrianarge_attach_sysctl(device_t dev)
211209802Sadrian{
212209802Sadrian	struct arge_softc *sc = device_get_softc(dev);
213209802Sadrian	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
214209802Sadrian	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
215209802Sadrian
216220355Sadrian#ifdef	ARGE_DEBUG
217209802Sadrian	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
218209802Sadrian		"debug", CTLFLAG_RW, &sc->arge_debug, 0,
219209802Sadrian		"arge interface debugging flags");
220220355Sadrian#endif
221209809Sadrian
222209809Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
223209809Sadrian		"tx_pkts_aligned", CTLFLAG_RW, &sc->stats.tx_pkts_aligned, 0,
224209809Sadrian		"number of TX aligned packets");
225209809Sadrian
226209809Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
227232628Sray		"tx_pkts_unaligned", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned,
228232628Sray		0, "number of TX unaligned packets");
229220354Sadrian
230220355Sadrian#ifdef	ARGE_DEBUG
231220355Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_prod",
232220355Sadrian	    CTLFLAG_RW, &sc->arge_cdata.arge_tx_prod, 0, "");
233220355Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cons",
234220355Sadrian	    CTLFLAG_RW, &sc->arge_cdata.arge_tx_cons, 0, "");
235220355Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cnt",
236220355Sadrian	    CTLFLAG_RW, &sc->arge_cdata.arge_tx_cnt, 0, "");
237220355Sadrian#endif
238209802Sadrian}
239209802Sadrian
240188808Sgonzostatic int
241188808Sgonzoarge_attach(device_t dev)
242188808Sgonzo{
243188808Sgonzo	uint8_t			eaddr[ETHER_ADDR_LEN];
244188808Sgonzo	struct ifnet		*ifp;
245188808Sgonzo	struct arge_softc	*sc;
246199234Sgonzo	int			error = 0, rid, phymask;
247192179Sgonzo	uint32_t		reg, rnd;
248199234Sgonzo	int			is_base_mac_empty, i, phys_total;
249199234Sgonzo	uint32_t		hint;
250220260Sadrian	long			eeprom_mac_addr = 0;
251188808Sgonzo
252188808Sgonzo	sc = device_get_softc(dev);
253188808Sgonzo	sc->arge_dev = dev;
254188808Sgonzo	sc->arge_mac_unit = device_get_unit(dev);
255188808Sgonzo
256220260Sadrian	/*
257220260Sadrian	 * Some units (eg the TP-Link WR-1043ND) do not have a convenient
258220260Sadrian	 * EEPROM location to read the ethernet MAC address from.
259220260Sadrian	 * OpenWRT simply snaffles it from a fixed location.
260220260Sadrian	 *
261220260Sadrian	 * Since multiple units seem to use this feature, include
262220260Sadrian	 * a method of setting the MAC address based on an flash location
263220260Sadrian	 * in CPU address space.
264220260Sadrian	 */
265220260Sadrian	if (sc->arge_mac_unit == 0 &&
266232627Sray	    resource_long_value(device_get_name(dev), device_get_unit(dev),
267220260Sadrian	    "eeprommac", &eeprom_mac_addr) == 0) {
268220260Sadrian		int i;
269232628Sray		const char *mac =
270232628Sray		    (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr);
271220260Sadrian		device_printf(dev, "Overriding MAC from EEPROM\n");
272220260Sadrian		for (i = 0; i < 6; i++) {
273220260Sadrian			ar711_base_mac[i] = mac[i];
274220260Sadrian		}
275220260Sadrian	}
276220260Sadrian
277232627Sray	KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)),
278188808Sgonzo	    ("if_arge: Only MAC0 and MAC1 supported"));
279188808Sgonzo
280188808Sgonzo	/*
281188808Sgonzo	 *  Get which PHY of 5 available we should use for this unit
282188808Sgonzo	 */
283232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
284199234Sgonzo	    "phymask", &phymask) != 0) {
285188808Sgonzo		/*
286232627Sray		 * Use port 4 (WAN) for GE0. For any other port use
287232627Sray		 * its PHY the same as its unit number
288188808Sgonzo		 */
289188808Sgonzo		if (sc->arge_mac_unit == 0)
290199234Sgonzo			phymask = (1 << 4);
291188808Sgonzo		else
292199234Sgonzo			/* Use all phys up to 4 */
293199234Sgonzo			phymask = (1 << 4) - 1;
294188808Sgonzo
295232628Sray		device_printf(dev, "No PHY specified, using mask %d\n",
296232628Sray		    phymask);
297188808Sgonzo	}
298188808Sgonzo
299199234Sgonzo	/*
300232627Sray	 *  Get default media & duplex mode, by default its Base100T
301199234Sgonzo	 *  and full duplex
302199234Sgonzo	 */
303232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
304199234Sgonzo	    "media", &hint) != 0)
305199234Sgonzo		hint = 0;
306188808Sgonzo
307199234Sgonzo	if (hint == 1000)
308199234Sgonzo		sc->arge_media_type = IFM_1000_T;
309199234Sgonzo	else
310199234Sgonzo		sc->arge_media_type = IFM_100_TX;
311199234Sgonzo
312232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
313199234Sgonzo	    "fduplex", &hint) != 0)
314199234Sgonzo		hint = 1;
315199234Sgonzo
316199234Sgonzo	if (hint)
317199234Sgonzo		sc->arge_duplex_mode = IFM_FDX;
318199234Sgonzo	else
319199234Sgonzo		sc->arge_duplex_mode = 0;
320199234Sgonzo
321199234Sgonzo	sc->arge_phymask = phymask;
322199234Sgonzo
323188808Sgonzo	mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
324188808Sgonzo	    MTX_DEF);
325188808Sgonzo	callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0);
326188808Sgonzo	TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc);
327188808Sgonzo
328188808Sgonzo	/* Map control/status registers. */
329188808Sgonzo	sc->arge_rid = 0;
330232627Sray	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
331188808Sgonzo	    &sc->arge_rid, RF_ACTIVE);
332188808Sgonzo
333188808Sgonzo	if (sc->arge_res == NULL) {
334188808Sgonzo		device_printf(dev, "couldn't map memory\n");
335188808Sgonzo		error = ENXIO;
336188808Sgonzo		goto fail;
337188808Sgonzo	}
338188808Sgonzo
339188808Sgonzo	/* Allocate interrupts */
340188808Sgonzo	rid = 0;
341232627Sray	sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
342188808Sgonzo	    RF_SHAREABLE | RF_ACTIVE);
343188808Sgonzo
344188808Sgonzo	if (sc->arge_irq == NULL) {
345188808Sgonzo		device_printf(dev, "couldn't map interrupt\n");
346188808Sgonzo		error = ENXIO;
347188808Sgonzo		goto fail;
348188808Sgonzo	}
349188808Sgonzo
350188808Sgonzo	/* Allocate ifnet structure. */
351188808Sgonzo	ifp = sc->arge_ifp = if_alloc(IFT_ETHER);
352188808Sgonzo
353188808Sgonzo	if (ifp == NULL) {
354188808Sgonzo		device_printf(dev, "couldn't allocate ifnet structure\n");
355188808Sgonzo		error = ENOSPC;
356188808Sgonzo		goto fail;
357188808Sgonzo	}
358188808Sgonzo
359188808Sgonzo	ifp->if_softc = sc;
360188808Sgonzo	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
361188808Sgonzo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
362188808Sgonzo	ifp->if_ioctl = arge_ioctl;
363188808Sgonzo	ifp->if_start = arge_start;
364188808Sgonzo	ifp->if_init = arge_init;
365198932Sgonzo	sc->arge_if_flags = ifp->if_flags;
366188808Sgonzo
367188808Sgonzo	/* XXX: add real size */
368207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
369207554Ssobomax	ifp->if_snd.ifq_maxlen = ifqmaxlen;
370188808Sgonzo	IFQ_SET_READY(&ifp->if_snd);
371188808Sgonzo
372188808Sgonzo	ifp->if_capenable = ifp->if_capabilities;
373192783Sgonzo#ifdef DEVICE_POLLING
374192783Sgonzo	ifp->if_capabilities |= IFCAP_POLLING;
375192783Sgonzo#endif
376188808Sgonzo
377192179Sgonzo	is_base_mac_empty = 1;
378192179Sgonzo	for (i = 0; i < ETHER_ADDR_LEN; i++) {
379192179Sgonzo		eaddr[i] = ar711_base_mac[i] & 0xff;
380192179Sgonzo		if (eaddr[i] != 0)
381192179Sgonzo			is_base_mac_empty = 0;
382192179Sgonzo	}
383188808Sgonzo
384192179Sgonzo	if (is_base_mac_empty) {
385192179Sgonzo		/*
386192179Sgonzo		 * No MAC address configured. Generate the random one.
387192179Sgonzo		 */
388198933Sgonzo		if  (bootverbose)
389232627Sray			device_printf(dev,
390192179Sgonzo			    "Generating random ethernet address.\n");
391192179Sgonzo
392192179Sgonzo		rnd = arc4random();
393192179Sgonzo		eaddr[0] = 'b';
394192179Sgonzo		eaddr[1] = 's';
395192179Sgonzo		eaddr[2] = 'd';
396192179Sgonzo		eaddr[3] = (rnd >> 24) & 0xff;
397192179Sgonzo		eaddr[4] = (rnd >> 16) & 0xff;
398192179Sgonzo		eaddr[5] = (rnd >> 8) & 0xff;
399192179Sgonzo	}
400192179Sgonzo
401198970Sgonzo	if (sc->arge_mac_unit != 0)
402198970Sgonzo		eaddr[5] +=  sc->arge_mac_unit;
403198970Sgonzo
404188808Sgonzo	if (arge_dma_alloc(sc) != 0) {
405188808Sgonzo		error = ENXIO;
406188808Sgonzo		goto fail;
407188808Sgonzo	}
408188808Sgonzo
409192569Sdwhite	/* Initialize the MAC block */
410232627Sray
411192569Sdwhite	/* Step 1. Soft-reset MAC */
412192569Sdwhite	ARGE_SET_BITS(sc, AR71XX_MAC_CFG1, MAC_CFG1_SOFT_RESET);
413192569Sdwhite	DELAY(20);
414192569Sdwhite
415192569Sdwhite	/* Step 2. Punt the MAC core from the central reset register */
416232628Sray	ar71xx_device_stop(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC :
417232628Sray	    RST_RESET_GE1_MAC);
418192569Sdwhite	DELAY(100);
419232628Sray	ar71xx_device_start(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC :
420232628Sray	    RST_RESET_GE1_MAC);
421192569Sdwhite
422192569Sdwhite	/* Step 3. Reconfigure MAC block */
423232627Sray	ARGE_WRITE(sc, AR71XX_MAC_CFG1,
424188808Sgonzo		MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE |
425188808Sgonzo		MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE);
426188808Sgonzo
427188808Sgonzo	reg = ARGE_READ(sc, AR71XX_MAC_CFG2);
428188808Sgonzo	reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ;
429188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg);
430188808Sgonzo
431188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536);
432188808Sgonzo
433188808Sgonzo	/* Reset MII bus */
434188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET);
435188808Sgonzo	DELAY(100);
436188808Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28);
437188808Sgonzo	DELAY(100);
438188808Sgonzo
439232627Sray	/*
440188808Sgonzo	 * Set all Ethernet address registers to the same initial values
441232627Sray	 * set all four addresses to 66-88-aa-cc-dd-ee
442188808Sgonzo	 */
443232627Sray	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1,
444232628Sray	    (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8) | eaddr[5]);
445192783Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (eaddr[0] << 8) | eaddr[1]);
446188808Sgonzo
447232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0,
448188808Sgonzo	    FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT);
449188808Sgonzo
450219589Sadrian	switch (ar71xx_soc) {
451219589Sadrian		case AR71XX_SOC_AR7240:
452219589Sadrian		case AR71XX_SOC_AR7241:
453219589Sadrian		case AR71XX_SOC_AR7242:
454219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0010ffff);
455219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x015500aa);
456219589Sadrian			break;
457219589Sadrian		default:
458219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000);
459219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff);
460219589Sadrian	}
461219589Sadrian
462232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH,
463192783Sgonzo	    FIFO_RX_FILTMATCH_DEFAULT);
464188808Sgonzo
465232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
466192783Sgonzo	    FIFO_RX_FILTMASK_DEFAULT);
467188808Sgonzo
468232627Sray	/*
469199234Sgonzo	 * Check if we have single-PHY MAC or multi-PHY
470199234Sgonzo	 */
471199234Sgonzo	phys_total = 0;
472199234Sgonzo	for (i = 0; i < ARGE_NPHY; i++)
473199234Sgonzo		if (phymask & (1 << i))
474199234Sgonzo			phys_total ++;
475199234Sgonzo
476199234Sgonzo	if (phys_total == 0) {
477199234Sgonzo		error = EINVAL;
478188808Sgonzo		goto fail;
479188808Sgonzo	}
480188808Sgonzo
481199234Sgonzo	if (phys_total == 1) {
482199234Sgonzo		/* Do MII setup. */
483213894Smarius		error = mii_attach(dev, &sc->arge_miibus, ifp,
484213894Smarius		    arge_ifmedia_upd, arge_ifmedia_sts, BMSR_DEFCAPMASK,
485213894Smarius		    MII_PHY_ANY, MII_OFFSET_ANY, 0);
486213894Smarius		if (error != 0) {
487213894Smarius			device_printf(dev, "attaching PHYs failed\n");
488199234Sgonzo			goto fail;
489199234Sgonzo		}
490199234Sgonzo	}
491199234Sgonzo	else {
492232627Sray		ifmedia_init(&sc->arge_ifmedia, 0,
493199234Sgonzo		    arge_multiphy_mediachange,
494199234Sgonzo		    arge_multiphy_mediastatus);
495199234Sgonzo		ifmedia_add(&sc->arge_ifmedia,
496232627Sray		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode,
497199234Sgonzo		    0, NULL);
498199234Sgonzo		ifmedia_set(&sc->arge_ifmedia,
499199234Sgonzo		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode);
500199234Sgonzo		arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode);
501199234Sgonzo	}
502199234Sgonzo
503188808Sgonzo	/* Call MI attach routine. */
504188808Sgonzo	ether_ifattach(ifp, eaddr);
505188808Sgonzo
506188808Sgonzo	/* Hook interrupt last to avoid having to lock softc */
507188808Sgonzo	error = bus_setup_intr(dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
508188808Sgonzo	    arge_intr_filter, arge_intr, sc, &sc->arge_intrhand);
509188808Sgonzo
510188808Sgonzo	if (error) {
511188808Sgonzo		device_printf(dev, "couldn't set up irq\n");
512188808Sgonzo		ether_ifdetach(ifp);
513188808Sgonzo		goto fail;
514188808Sgonzo	}
515188808Sgonzo
516209802Sadrian	/* setup sysctl variables */
517209802Sadrian	arge_attach_sysctl(dev);
518209802Sadrian
519188808Sgonzofail:
520232627Sray	if (error)
521188808Sgonzo		arge_detach(dev);
522188808Sgonzo
523188808Sgonzo	return (error);
524188808Sgonzo}
525188808Sgonzo
526188808Sgonzostatic int
527188808Sgonzoarge_detach(device_t dev)
528188808Sgonzo{
529192783Sgonzo	struct arge_softc	*sc = device_get_softc(dev);
530188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
531188808Sgonzo
532232628Sray	KASSERT(mtx_initialized(&sc->arge_mtx),
533232628Sray	    ("arge mutex not initialized"));
534188808Sgonzo
535188808Sgonzo	/* These should only be active if attach succeeded */
536188808Sgonzo	if (device_is_attached(dev)) {
537188808Sgonzo		ARGE_LOCK(sc);
538188808Sgonzo		sc->arge_detach = 1;
539192783Sgonzo#ifdef DEVICE_POLLING
540192783Sgonzo		if (ifp->if_capenable & IFCAP_POLLING)
541192783Sgonzo			ether_poll_deregister(ifp);
542192783Sgonzo#endif
543192783Sgonzo
544188808Sgonzo		arge_stop(sc);
545188808Sgonzo		ARGE_UNLOCK(sc);
546188808Sgonzo		taskqueue_drain(taskqueue_swi, &sc->arge_link_task);
547188808Sgonzo		ether_ifdetach(ifp);
548188808Sgonzo	}
549188808Sgonzo
550188808Sgonzo	if (sc->arge_miibus)
551188808Sgonzo		device_delete_child(dev, sc->arge_miibus);
552199234Sgonzo
553188808Sgonzo	bus_generic_detach(dev);
554188808Sgonzo
555188808Sgonzo	if (sc->arge_intrhand)
556188808Sgonzo		bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand);
557188808Sgonzo
558188808Sgonzo	if (sc->arge_res)
559232627Sray		bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid,
560188808Sgonzo		    sc->arge_res);
561188808Sgonzo
562188808Sgonzo	if (ifp)
563188808Sgonzo		if_free(ifp);
564188808Sgonzo
565188808Sgonzo	arge_dma_free(sc);
566188808Sgonzo
567188808Sgonzo	mtx_destroy(&sc->arge_mtx);
568188808Sgonzo
569188808Sgonzo	return (0);
570188808Sgonzo
571188808Sgonzo}
572188808Sgonzo
573188808Sgonzostatic int
574188808Sgonzoarge_suspend(device_t dev)
575188808Sgonzo{
576188808Sgonzo
577188808Sgonzo	panic("%s", __func__);
578188808Sgonzo	return 0;
579188808Sgonzo}
580188808Sgonzo
581188808Sgonzostatic int
582188808Sgonzoarge_resume(device_t dev)
583188808Sgonzo{
584188808Sgonzo
585188808Sgonzo	panic("%s", __func__);
586188808Sgonzo	return 0;
587188808Sgonzo}
588188808Sgonzo
589194059Sgonzostatic int
590188808Sgonzoarge_shutdown(device_t dev)
591188808Sgonzo{
592188808Sgonzo	struct arge_softc	*sc;
593188808Sgonzo
594188808Sgonzo	sc = device_get_softc(dev);
595188808Sgonzo
596188808Sgonzo	ARGE_LOCK(sc);
597188808Sgonzo	arge_stop(sc);
598188808Sgonzo	ARGE_UNLOCK(sc);
599194059Sgonzo
600194059Sgonzo	return (0);
601188808Sgonzo}
602188808Sgonzo
603188808Sgonzostatic int
604188808Sgonzoarge_miibus_readreg(device_t dev, int phy, int reg)
605188808Sgonzo{
606188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
607188808Sgonzo	int i, result;
608232627Sray	uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT)
609188808Sgonzo	    | (reg & MAC_MII_REG_MASK);
610188808Sgonzo
611199234Sgonzo	if ((sc->arge_phymask  & (1 << phy)) == 0)
612188808Sgonzo		return (0);
613188808Sgonzo
614199038Sgonzo	mtx_lock(&miibus_mtx);
615199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
616199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr);
617199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
618188808Sgonzo
619188808Sgonzo	i = ARGE_MII_TIMEOUT;
620232627Sray	while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) &
621188808Sgonzo	    MAC_MII_INDICATOR_BUSY) && (i--))
622188808Sgonzo		DELAY(5);
623188808Sgonzo
624188808Sgonzo	if (i < 0) {
625199038Sgonzo		mtx_unlock(&miibus_mtx);
626220354Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__);
627188808Sgonzo		/* XXX: return ERRNO istead? */
628188808Sgonzo		return (-1);
629188808Sgonzo	}
630188808Sgonzo
631199038Sgonzo	result = ARGE_MII_READ(AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
632199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
633199038Sgonzo	mtx_unlock(&miibus_mtx);
634199038Sgonzo
635232628Sray	ARGEDEBUG(sc, ARGE_DBG_MII,
636232628Sray	    "%s: phy=%d, reg=%02x, value[%08x]=%04x\n",
637232628Sray	    __func__, phy, reg, addr, result);
638188808Sgonzo
639188808Sgonzo	return (result);
640188808Sgonzo}
641188808Sgonzo
642188808Sgonzostatic int
643188808Sgonzoarge_miibus_writereg(device_t dev, int phy, int reg, int data)
644188808Sgonzo{
645188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
646188808Sgonzo	int i;
647232627Sray	uint32_t addr =
648196794Sgonzo	    (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK);
649188808Sgonzo
650199038Sgonzo
651199234Sgonzo	if ((sc->arge_phymask  & (1 << phy)) == 0)
652199038Sgonzo		return (-1);
653199038Sgonzo
654232628Sray	ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n",
655232628Sray	    __func__, phy, reg, data);
656188808Sgonzo
657199038Sgonzo	mtx_lock(&miibus_mtx);
658199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr);
659199038Sgonzo	ARGE_MII_WRITE(AR71XX_MAC_MII_CONTROL, data);
660188808Sgonzo
661188808Sgonzo	i = ARGE_MII_TIMEOUT;
662232627Sray	while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) &
663188808Sgonzo	    MAC_MII_INDICATOR_BUSY) && (i--))
664188808Sgonzo		DELAY(5);
665188808Sgonzo
666199038Sgonzo	mtx_unlock(&miibus_mtx);
667199038Sgonzo
668188808Sgonzo	if (i < 0) {
669220354Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__);
670188808Sgonzo		/* XXX: return ERRNO istead? */
671188808Sgonzo		return (-1);
672188808Sgonzo	}
673188808Sgonzo
674188808Sgonzo	return (0);
675188808Sgonzo}
676188808Sgonzo
677188808Sgonzostatic void
678188808Sgonzoarge_miibus_statchg(device_t dev)
679188808Sgonzo{
680232627Sray	struct arge_softc	*sc;
681188808Sgonzo
682188808Sgonzo	sc = device_get_softc(dev);
683188808Sgonzo	taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task);
684188808Sgonzo}
685188808Sgonzo
686188808Sgonzostatic void
687188808Sgonzoarge_link_task(void *arg, int pending)
688188808Sgonzo{
689188808Sgonzo	struct arge_softc	*sc;
690232914Sadrian	sc = (struct arge_softc *)arg;
691232914Sadrian
692232914Sadrian	ARGE_LOCK(sc);
693232914Sadrian	arge_update_link_locked(sc);
694232914Sadrian	ARGE_UNLOCK(sc);
695232914Sadrian}
696232914Sadrian
697232914Sadrianstatic void
698232914Sadrianarge_update_link_locked(struct arge_softc *sc)
699232914Sadrian{
700188808Sgonzo	struct mii_data		*mii;
701188808Sgonzo	struct ifnet		*ifp;
702199234Sgonzo	uint32_t		media, duplex;
703188808Sgonzo
704188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
705188808Sgonzo	ifp = sc->arge_ifp;
706188808Sgonzo	if (mii == NULL || ifp == NULL ||
707188808Sgonzo	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
708188808Sgonzo		return;
709188808Sgonzo	}
710188808Sgonzo
711188808Sgonzo	if (mii->mii_media_status & IFM_ACTIVE) {
712188808Sgonzo
713188808Sgonzo		media = IFM_SUBTYPE(mii->mii_media_active);
714188808Sgonzo
715188808Sgonzo		if (media != IFM_NONE) {
716188808Sgonzo			sc->arge_link_status = 1;
717199234Sgonzo			duplex = mii->mii_media_active & IFM_GMASK;
718199234Sgonzo			arge_set_pll(sc, media, duplex);
719199234Sgonzo		}
720232914Sadrian	} else {
721199234Sgonzo		sc->arge_link_status = 0;
722232914Sadrian	}
723199234Sgonzo}
724192783Sgonzo
725199234Sgonzostatic void
726199234Sgonzoarge_set_pll(struct arge_softc *sc, int media, int duplex)
727199234Sgonzo{
728211511Sadrian	uint32_t		cfg, ifcontrol, rx_filtmask;
729219589Sadrian	uint32_t		fifo_tx;
730211511Sadrian	int if_speed;
731192783Sgonzo
732199234Sgonzo	cfg = ARGE_READ(sc, AR71XX_MAC_CFG2);
733232627Sray	cfg &= ~(MAC_CFG2_IFACE_MODE_1000
734232627Sray	    | MAC_CFG2_IFACE_MODE_10_100
735199234Sgonzo	    | MAC_CFG2_FULL_DUPLEX);
736188808Sgonzo
737199234Sgonzo	if (duplex == IFM_FDX)
738199234Sgonzo		cfg |= MAC_CFG2_FULL_DUPLEX;
739188808Sgonzo
740199234Sgonzo	ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL);
741199234Sgonzo	ifcontrol &= ~MAC_IFCONTROL_SPEED;
742232627Sray	rx_filtmask =
743199234Sgonzo	    ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK);
744199234Sgonzo	rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE;
745188808Sgonzo
746199234Sgonzo	switch(media) {
747199234Sgonzo	case IFM_10_T:
748199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
749211511Sadrian		if_speed = 10;
750199234Sgonzo		break;
751199234Sgonzo	case IFM_100_TX:
752199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
753199234Sgonzo		ifcontrol |= MAC_IFCONTROL_SPEED;
754211511Sadrian		if_speed = 100;
755199234Sgonzo		break;
756199234Sgonzo	case IFM_1000_T:
757199234Sgonzo	case IFM_1000_SX:
758199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_1000;
759199234Sgonzo		rx_filtmask |= FIFO_RX_MASK_BYTE_MODE;
760211511Sadrian		if_speed = 1000;
761199234Sgonzo		break;
762199234Sgonzo	default:
763211511Sadrian		if_speed = 100;
764232627Sray		device_printf(sc->arge_dev,
765199234Sgonzo		    "Unknown media %d\n", media);
766199234Sgonzo	}
767188808Sgonzo
768219589Sadrian	switch (ar71xx_soc) {
769219589Sadrian		case AR71XX_SOC_AR7240:
770219589Sadrian		case AR71XX_SOC_AR7241:
771219589Sadrian		case AR71XX_SOC_AR7242:
772219589Sadrian			fifo_tx = 0x01f00140;
773219589Sadrian			break;
774219589Sadrian		case AR71XX_SOC_AR9130:
775219589Sadrian		case AR71XX_SOC_AR9132:
776219589Sadrian			fifo_tx = 0x00780fff;
777219589Sadrian			break;
778219589Sadrian		default:
779219589Sadrian			fifo_tx = 0x008001ff;
780219589Sadrian	}
781188808Sgonzo
782199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg);
783199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol);
784232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
785199234Sgonzo	    rx_filtmask);
786219589Sadrian	ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, fifo_tx);
787188808Sgonzo
788199234Sgonzo	/* set PLL registers */
789228018Sray	ar71xx_device_set_pll_ge(sc->arge_mac_unit, if_speed);
790188808Sgonzo}
791188808Sgonzo
792199234Sgonzo
793188808Sgonzostatic void
794188808Sgonzoarge_reset_dma(struct arge_softc *sc)
795188808Sgonzo{
796188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0);
797188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0);
798188808Sgonzo
799188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0);
800188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0);
801188808Sgonzo
802188808Sgonzo	/* Clear all possible RX interrupts */
803192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD)
804188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
805188808Sgonzo
806232627Sray	/*
807188808Sgonzo	 * Clear all possible TX interrupts
808188808Sgonzo	 */
809192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT)
810188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
811188808Sgonzo
812232627Sray	/*
813188808Sgonzo	 * Now Rx/Tx errors
814188808Sgonzo	 */
815232627Sray	ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS,
816188808Sgonzo	    DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW);
817232627Sray	ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS,
818188808Sgonzo	    DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN);
819232912Sadrian
820232912Sadrian	/*
821232912Sadrian	 * Force a DDR flush so any pending data is properly
822232912Sadrian	 * flushed to RAM before underlying buffers are freed.
823232912Sadrian	 */
824232912Sadrian	arge_flush_ddr(sc);
825188808Sgonzo}
826188808Sgonzo
827188808Sgonzo
828188808Sgonzo
829188808Sgonzostatic void
830188808Sgonzoarge_init(void *xsc)
831188808Sgonzo{
832188808Sgonzo	struct arge_softc	 *sc = xsc;
833188808Sgonzo
834188808Sgonzo	ARGE_LOCK(sc);
835188808Sgonzo	arge_init_locked(sc);
836188808Sgonzo	ARGE_UNLOCK(sc);
837188808Sgonzo}
838188808Sgonzo
839188808Sgonzostatic void
840188808Sgonzoarge_init_locked(struct arge_softc *sc)
841188808Sgonzo{
842188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
843188808Sgonzo	struct mii_data		*mii;
844188808Sgonzo
845188808Sgonzo	ARGE_LOCK_ASSERT(sc);
846188808Sgonzo
847188808Sgonzo	arge_stop(sc);
848188808Sgonzo
849188808Sgonzo	/* Init circular RX list. */
850188808Sgonzo	if (arge_rx_ring_init(sc) != 0) {
851188808Sgonzo		device_printf(sc->arge_dev,
852188808Sgonzo		    "initialization failed: no memory for rx buffers\n");
853188808Sgonzo		arge_stop(sc);
854188808Sgonzo		return;
855188808Sgonzo	}
856188808Sgonzo
857188808Sgonzo	/* Init tx descriptors. */
858188808Sgonzo	arge_tx_ring_init(sc);
859188808Sgonzo
860188808Sgonzo	arge_reset_dma(sc);
861188808Sgonzo
862199234Sgonzo	if (sc->arge_miibus) {
863199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
864199234Sgonzo		mii_mediachg(mii);
865199234Sgonzo	}
866199234Sgonzo	else {
867199234Sgonzo		/*
868199234Sgonzo		 * Sun always shines over multiPHY interface
869199234Sgonzo		 */
870199234Sgonzo		sc->arge_link_status = 1;
871199234Sgonzo	}
872199234Sgonzo
873188808Sgonzo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
874188808Sgonzo	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
875188808Sgonzo
876232914Sadrian	if (sc->arge_miibus) {
877199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
878232914Sadrian		arge_update_link_locked(sc);
879232914Sadrian	}
880192783Sgonzo
881188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0));
882188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0));
883188808Sgonzo
884188808Sgonzo	/* Start listening */
885188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
886188808Sgonzo
887188808Sgonzo	/* Enable interrupts */
888188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
889188808Sgonzo}
890188808Sgonzo
891188808Sgonzo/*
892209807Sadrian * Return whether the mbuf chain is correctly aligned
893209807Sadrian * for the arge TX engine.
894209807Sadrian *
895209807Sadrian * The TX engine requires each fragment to be aligned to a
896209807Sadrian * 4 byte boundary and the size of each fragment except
897209807Sadrian * the last to be a multiple of 4 bytes.
898209807Sadrian */
899209807Sadrianstatic int
900209807Sadrianarge_mbuf_chain_is_tx_aligned(struct mbuf *m0)
901209807Sadrian{
902209807Sadrian	struct mbuf *m;
903209807Sadrian
904209807Sadrian	for (m = m0; m != NULL; m = m->m_next) {
905209807Sadrian		if((mtod(m, intptr_t) & 3) != 0)
906209807Sadrian			return 0;
907209807Sadrian		if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0))
908209807Sadrian			return 0;
909209807Sadrian	}
910209807Sadrian	return 1;
911209807Sadrian}
912209807Sadrian
913209807Sadrian/*
914188808Sgonzo * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
915188808Sgonzo * pointers to the fragment pointers.
916188808Sgonzo */
917188808Sgonzostatic int
918188808Sgonzoarge_encap(struct arge_softc *sc, struct mbuf **m_head)
919188808Sgonzo{
920188808Sgonzo	struct arge_txdesc	*txd;
921188808Sgonzo	struct arge_desc	*desc, *prev_desc;
922188808Sgonzo	bus_dma_segment_t	txsegs[ARGE_MAXFRAGS];
923192569Sdwhite	int			error, i, nsegs, prod, prev_prod;
924192783Sgonzo	struct mbuf		*m;
925188808Sgonzo
926188808Sgonzo	ARGE_LOCK_ASSERT(sc);
927188808Sgonzo
928192783Sgonzo	/*
929192783Sgonzo	 * Fix mbuf chain, all fragments should be 4 bytes aligned and
930192783Sgonzo	 * even 4 bytes
931192783Sgonzo	 */
932192783Sgonzo	m = *m_head;
933209807Sadrian	if (! arge_mbuf_chain_is_tx_aligned(m)) {
934209809Sadrian		sc->stats.tx_pkts_unaligned++;
935192783Sgonzo		m = m_defrag(*m_head, M_DONTWAIT);
936192783Sgonzo		if (m == NULL) {
937192783Sgonzo			*m_head = NULL;
938192783Sgonzo			return (ENOBUFS);
939192783Sgonzo		}
940192783Sgonzo		*m_head = m;
941209809Sadrian	} else
942209809Sadrian		sc->stats.tx_pkts_aligned++;
943192783Sgonzo
944188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
945188808Sgonzo	txd = &sc->arge_cdata.arge_txdesc[prod];
946232627Sray	error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag,
947188808Sgonzo	    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
948188808Sgonzo
949188808Sgonzo	if (error == EFBIG) {
950188808Sgonzo		panic("EFBIG");
951188808Sgonzo	} else if (error != 0)
952188808Sgonzo		return (error);
953188808Sgonzo
954188808Sgonzo	if (nsegs == 0) {
955188808Sgonzo		m_freem(*m_head);
956188808Sgonzo		*m_head = NULL;
957188808Sgonzo		return (EIO);
958188808Sgonzo	}
959188808Sgonzo
960188808Sgonzo	/* Check number of available descriptors. */
961188808Sgonzo	if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 1)) {
962188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
963188808Sgonzo		return (ENOBUFS);
964188808Sgonzo	}
965188808Sgonzo
966188808Sgonzo	txd->tx_m = *m_head;
967188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
968188808Sgonzo	    BUS_DMASYNC_PREWRITE);
969188808Sgonzo
970232627Sray	/*
971188808Sgonzo	 * Make a list of descriptors for this packet. DMA controller will
972188808Sgonzo	 * walk through it while arge_link is not zero.
973188808Sgonzo	 */
974188808Sgonzo	prev_prod = prod;
975188808Sgonzo	desc = prev_desc = NULL;
976188808Sgonzo	for (i = 0; i < nsegs; i++) {
977188808Sgonzo		desc = &sc->arge_rdata.arge_tx_ring[prod];
978188808Sgonzo		desc->packet_ctrl = ARGE_DMASIZE(txsegs[i].ds_len);
979188808Sgonzo
980192783Sgonzo		if (txsegs[i].ds_addr & 3)
981192783Sgonzo			panic("TX packet address unaligned\n");
982192783Sgonzo
983188808Sgonzo		desc->packet_addr = txsegs[i].ds_addr;
984232627Sray
985188808Sgonzo		/* link with previous descriptor */
986188808Sgonzo		if (prev_desc)
987188808Sgonzo			prev_desc->packet_ctrl |= ARGE_DESC_MORE;
988188808Sgonzo
989188808Sgonzo		sc->arge_cdata.arge_tx_cnt++;
990188808Sgonzo		prev_desc = desc;
991188808Sgonzo		ARGE_INC(prod, ARGE_TX_RING_COUNT);
992188808Sgonzo	}
993188808Sgonzo
994188808Sgonzo	/* Update producer index. */
995188808Sgonzo	sc->arge_cdata.arge_tx_prod = prod;
996188808Sgonzo
997188808Sgonzo	/* Sync descriptors. */
998188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
999188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1000188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1001188808Sgonzo
1002188808Sgonzo	/* Start transmitting */
1003232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: setting DMA_TX_CONTROL_EN\n",
1004232628Sray	    __func__);
1005188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN);
1006188808Sgonzo	return (0);
1007188808Sgonzo}
1008188808Sgonzo
1009188808Sgonzostatic void
1010188808Sgonzoarge_start(struct ifnet *ifp)
1011188808Sgonzo{
1012188808Sgonzo	struct arge_softc	 *sc;
1013188808Sgonzo
1014188808Sgonzo	sc = ifp->if_softc;
1015188808Sgonzo
1016188808Sgonzo	ARGE_LOCK(sc);
1017188808Sgonzo	arge_start_locked(ifp);
1018188808Sgonzo	ARGE_UNLOCK(sc);
1019188808Sgonzo}
1020188808Sgonzo
1021188808Sgonzostatic void
1022188808Sgonzoarge_start_locked(struct ifnet *ifp)
1023188808Sgonzo{
1024188808Sgonzo	struct arge_softc	*sc;
1025188808Sgonzo	struct mbuf		*m_head;
1026220356Sadrian	int			enq = 0;
1027188808Sgonzo
1028188808Sgonzo	sc = ifp->if_softc;
1029188808Sgonzo
1030188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1031188808Sgonzo
1032220356Sadrian	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: beginning\n", __func__);
1033220356Sadrian
1034188808Sgonzo	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1035188808Sgonzo	    IFF_DRV_RUNNING || sc->arge_link_status == 0 )
1036188808Sgonzo		return;
1037188808Sgonzo
1038220356Sadrian	/*
1039220356Sadrian	 * Before we go any further, check whether we're already full.
1040220356Sadrian	 * The below check errors out immediately if the ring is full
1041220356Sadrian	 * and never gets a chance to set this flag. Although it's
1042220356Sadrian	 * likely never needed, this at least avoids an unexpected
1043220356Sadrian	 * situation.
1044220356Sadrian	 */
1045220356Sadrian	if (sc->arge_cdata.arge_tx_cnt >= ARGE_TX_RING_COUNT - 2) {
1046220356Sadrian		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1047232628Sray		ARGEDEBUG(sc, ARGE_DBG_ERR,
1048232628Sray		    "%s: tx_cnt %d >= max %d; setting IFF_DRV_OACTIVE\n",
1049232628Sray		    __func__, sc->arge_cdata.arge_tx_cnt,
1050232628Sray		    ARGE_TX_RING_COUNT - 2);
1051220356Sadrian		return;
1052220356Sadrian	}
1053220356Sadrian
1054188808Sgonzo	arge_flush_ddr(sc);
1055188808Sgonzo
1056188808Sgonzo	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
1057188808Sgonzo	    sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) {
1058188808Sgonzo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
1059188808Sgonzo		if (m_head == NULL)
1060188808Sgonzo			break;
1061188808Sgonzo
1062188808Sgonzo
1063188808Sgonzo		/*
1064188808Sgonzo		 * Pack the data into the transmit ring.
1065188808Sgonzo		 */
1066188808Sgonzo		if (arge_encap(sc, &m_head)) {
1067188808Sgonzo			if (m_head == NULL)
1068188808Sgonzo				break;
1069188808Sgonzo			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1070188808Sgonzo			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1071188808Sgonzo			break;
1072188808Sgonzo		}
1073188808Sgonzo
1074188808Sgonzo		enq++;
1075188808Sgonzo		/*
1076188808Sgonzo		 * If there's a BPF listener, bounce a copy of this frame
1077188808Sgonzo		 * to him.
1078188808Sgonzo		 */
1079188808Sgonzo		ETHER_BPF_MTAP(ifp, m_head);
1080188808Sgonzo	}
1081232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: finished; queued %d packets\n",
1082232628Sray	    __func__, enq);
1083188808Sgonzo}
1084188808Sgonzo
1085188808Sgonzostatic void
1086188808Sgonzoarge_stop(struct arge_softc *sc)
1087188808Sgonzo{
1088188808Sgonzo	struct ifnet	    *ifp;
1089188808Sgonzo
1090188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1091188808Sgonzo
1092188808Sgonzo	ifp = sc->arge_ifp;
1093188808Sgonzo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1094199234Sgonzo	if (sc->arge_miibus)
1095199234Sgonzo		callout_stop(&sc->arge_stat_callout);
1096188808Sgonzo
1097188808Sgonzo	/* mask out interrupts */
1098188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1099188808Sgonzo
1100188808Sgonzo	arge_reset_dma(sc);
1101232912Sadrian
1102232912Sadrian	/* Flush FIFO and free any existing mbufs */
1103232912Sadrian	arge_flush_ddr(sc);
1104232912Sadrian	arge_rx_ring_free(sc);
1105188808Sgonzo}
1106188808Sgonzo
1107188808Sgonzo
1108188808Sgonzostatic int
1109188808Sgonzoarge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1110188808Sgonzo{
1111188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1112188808Sgonzo	struct ifreq		*ifr = (struct ifreq *) data;
1113188808Sgonzo	struct mii_data		*mii;
1114188808Sgonzo	int			error;
1115192783Sgonzo#ifdef DEVICE_POLLING
1116192783Sgonzo	int			mask;
1117192783Sgonzo#endif
1118188808Sgonzo
1119188808Sgonzo	switch (command) {
1120188808Sgonzo	case SIOCSIFFLAGS:
1121198932Sgonzo		ARGE_LOCK(sc);
1122198932Sgonzo		if ((ifp->if_flags & IFF_UP) != 0) {
1123198932Sgonzo			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1124198932Sgonzo				if (((ifp->if_flags ^ sc->arge_if_flags)
1125198939Sgonzo				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0) {
1126198939Sgonzo					/* XXX: handle promisc & multi flags */
1127198939Sgonzo				}
1128232627Sray
1129198932Sgonzo			} else {
1130198932Sgonzo				if (!sc->arge_detach)
1131198932Sgonzo					arge_init_locked(sc);
1132198932Sgonzo			}
1133198932Sgonzo		} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1134198932Sgonzo			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1135198932Sgonzo			arge_stop(sc);
1136198932Sgonzo		}
1137198932Sgonzo		sc->arge_if_flags = ifp->if_flags;
1138198932Sgonzo		ARGE_UNLOCK(sc);
1139188808Sgonzo		error = 0;
1140188808Sgonzo		break;
1141188808Sgonzo	case SIOCADDMULTI:
1142188808Sgonzo	case SIOCDELMULTI:
1143198932Sgonzo		/* XXX: implement SIOCDELMULTI */
1144188808Sgonzo		error = 0;
1145188808Sgonzo		break;
1146188808Sgonzo	case SIOCGIFMEDIA:
1147188808Sgonzo	case SIOCSIFMEDIA:
1148199234Sgonzo		if (sc->arge_miibus) {
1149199234Sgonzo			mii = device_get_softc(sc->arge_miibus);
1150232628Sray			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
1151232628Sray			    command);
1152199234Sgonzo		}
1153232627Sray		else
1154232628Sray			error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia,
1155232628Sray			    command);
1156188808Sgonzo		break;
1157198933Sgonzo	case SIOCSIFCAP:
1158198932Sgonzo		/* XXX: Check other capabilities */
1159192783Sgonzo#ifdef DEVICE_POLLING
1160198933Sgonzo		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
1161198933Sgonzo		if (mask & IFCAP_POLLING) {
1162198933Sgonzo			if (ifr->ifr_reqcap & IFCAP_POLLING) {
1163192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1164198933Sgonzo				error = ether_poll_register(arge_poll, ifp);
1165198933Sgonzo				if (error)
1166198933Sgonzo					return error;
1167198933Sgonzo				ARGE_LOCK(sc);
1168198933Sgonzo				ifp->if_capenable |= IFCAP_POLLING;
1169198933Sgonzo				ARGE_UNLOCK(sc);
1170198933Sgonzo			} else {
1171192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1172198933Sgonzo				error = ether_poll_deregister(ifp);
1173198933Sgonzo				ARGE_LOCK(sc);
1174198933Sgonzo				ifp->if_capenable &= ~IFCAP_POLLING;
1175198933Sgonzo				ARGE_UNLOCK(sc);
1176198933Sgonzo			}
1177198933Sgonzo		}
1178198932Sgonzo		error = 0;
1179198933Sgonzo		break;
1180192783Sgonzo#endif
1181188808Sgonzo	default:
1182188808Sgonzo		error = ether_ioctl(ifp, command, data);
1183188808Sgonzo		break;
1184188808Sgonzo	}
1185188808Sgonzo
1186188808Sgonzo	return (error);
1187188808Sgonzo}
1188188808Sgonzo
1189188808Sgonzo/*
1190188808Sgonzo * Set media options.
1191188808Sgonzo */
1192188808Sgonzostatic int
1193188808Sgonzoarge_ifmedia_upd(struct ifnet *ifp)
1194188808Sgonzo{
1195188808Sgonzo	struct arge_softc		*sc;
1196188808Sgonzo	struct mii_data		*mii;
1197188808Sgonzo	struct mii_softc	*miisc;
1198188808Sgonzo	int			error;
1199188808Sgonzo
1200188808Sgonzo	sc = ifp->if_softc;
1201188808Sgonzo	ARGE_LOCK(sc);
1202188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1203221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1204221407Smarius		PHY_RESET(miisc);
1205188808Sgonzo	error = mii_mediachg(mii);
1206188808Sgonzo	ARGE_UNLOCK(sc);
1207188808Sgonzo
1208188808Sgonzo	return (error);
1209188808Sgonzo}
1210188808Sgonzo
1211188808Sgonzo/*
1212188808Sgonzo * Report current media status.
1213188808Sgonzo */
1214188808Sgonzostatic void
1215188808Sgonzoarge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1216188808Sgonzo{
1217188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1218188808Sgonzo	struct mii_data		*mii;
1219188808Sgonzo
1220188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1221188808Sgonzo	ARGE_LOCK(sc);
1222188808Sgonzo	mii_pollstat(mii);
1223188808Sgonzo	ifmr->ifm_active = mii->mii_media_active;
1224188808Sgonzo	ifmr->ifm_status = mii->mii_media_status;
1225226478Syongari	ARGE_UNLOCK(sc);
1226188808Sgonzo}
1227188808Sgonzo
1228188808Sgonzostruct arge_dmamap_arg {
1229188808Sgonzo	bus_addr_t	arge_busaddr;
1230188808Sgonzo};
1231188808Sgonzo
1232188808Sgonzostatic void
1233188808Sgonzoarge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1234188808Sgonzo{
1235188808Sgonzo	struct arge_dmamap_arg	*ctx;
1236188808Sgonzo
1237188808Sgonzo	if (error != 0)
1238188808Sgonzo		return;
1239188808Sgonzo	ctx = arg;
1240188808Sgonzo	ctx->arge_busaddr = segs[0].ds_addr;
1241188808Sgonzo}
1242188808Sgonzo
1243188808Sgonzostatic int
1244188808Sgonzoarge_dma_alloc(struct arge_softc *sc)
1245188808Sgonzo{
1246188808Sgonzo	struct arge_dmamap_arg	ctx;
1247188808Sgonzo	struct arge_txdesc	*txd;
1248188808Sgonzo	struct arge_rxdesc	*rxd;
1249188808Sgonzo	int			error, i;
1250188808Sgonzo
1251188808Sgonzo	/* Create parent DMA tag. */
1252188808Sgonzo	error = bus_dma_tag_create(
1253188808Sgonzo	    bus_get_dma_tag(sc->arge_dev),	/* parent */
1254188808Sgonzo	    1, 0,			/* alignment, boundary */
1255188808Sgonzo	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1256188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1257188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1258188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
1259188808Sgonzo	    0,				/* nsegments */
1260188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1261188808Sgonzo	    0,				/* flags */
1262188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1263188808Sgonzo	    &sc->arge_cdata.arge_parent_tag);
1264188808Sgonzo	if (error != 0) {
1265232628Sray		device_printf(sc->arge_dev,
1266232628Sray		    "failed to create parent DMA tag\n");
1267188808Sgonzo		goto fail;
1268188808Sgonzo	}
1269188808Sgonzo	/* Create tag for Tx ring. */
1270188808Sgonzo	error = bus_dma_tag_create(
1271188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1272188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1273188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1274188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1275188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1276188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsize */
1277188808Sgonzo	    1,				/* nsegments */
1278188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsegsize */
1279188808Sgonzo	    0,				/* flags */
1280188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1281188808Sgonzo	    &sc->arge_cdata.arge_tx_ring_tag);
1282188808Sgonzo	if (error != 0) {
1283232628Sray		device_printf(sc->arge_dev,
1284232628Sray		    "failed to create Tx ring DMA tag\n");
1285188808Sgonzo		goto fail;
1286188808Sgonzo	}
1287188808Sgonzo
1288188808Sgonzo	/* Create tag for Rx ring. */
1289188808Sgonzo	error = bus_dma_tag_create(
1290188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1291188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1292188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1293188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1294188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1295188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsize */
1296188808Sgonzo	    1,				/* nsegments */
1297188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsegsize */
1298188808Sgonzo	    0,				/* flags */
1299188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1300188808Sgonzo	    &sc->arge_cdata.arge_rx_ring_tag);
1301188808Sgonzo	if (error != 0) {
1302232628Sray		device_printf(sc->arge_dev,
1303232628Sray		    "failed to create Rx ring DMA tag\n");
1304188808Sgonzo		goto fail;
1305188808Sgonzo	}
1306188808Sgonzo
1307188808Sgonzo	/* Create tag for Tx buffers. */
1308188808Sgonzo	error = bus_dma_tag_create(
1309188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1310188808Sgonzo	    sizeof(uint32_t), 0,	/* alignment, boundary */
1311188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1312188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1313188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1314188808Sgonzo	    MCLBYTES * ARGE_MAXFRAGS,	/* maxsize */
1315188808Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1316188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1317188808Sgonzo	    0,				/* flags */
1318188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1319188808Sgonzo	    &sc->arge_cdata.arge_tx_tag);
1320188808Sgonzo	if (error != 0) {
1321188808Sgonzo		device_printf(sc->arge_dev, "failed to create Tx DMA tag\n");
1322188808Sgonzo		goto fail;
1323188808Sgonzo	}
1324188808Sgonzo
1325188808Sgonzo	/* Create tag for Rx buffers. */
1326188808Sgonzo	error = bus_dma_tag_create(
1327188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1328188808Sgonzo	    ARGE_RX_ALIGN, 0,		/* alignment, boundary */
1329188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1330188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1331188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1332188808Sgonzo	    MCLBYTES,			/* maxsize */
1333192821Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1334188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1335188808Sgonzo	    0,				/* flags */
1336188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1337188808Sgonzo	    &sc->arge_cdata.arge_rx_tag);
1338188808Sgonzo	if (error != 0) {
1339188808Sgonzo		device_printf(sc->arge_dev, "failed to create Rx DMA tag\n");
1340188808Sgonzo		goto fail;
1341188808Sgonzo	}
1342188808Sgonzo
1343188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
1344188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag,
1345188808Sgonzo	    (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK |
1346232628Sray	    BUS_DMA_COHERENT | BUS_DMA_ZERO,
1347232628Sray	    &sc->arge_cdata.arge_tx_ring_map);
1348188808Sgonzo	if (error != 0) {
1349188808Sgonzo		device_printf(sc->arge_dev,
1350188808Sgonzo		    "failed to allocate DMA'able memory for Tx ring\n");
1351188808Sgonzo		goto fail;
1352188808Sgonzo	}
1353188808Sgonzo
1354188808Sgonzo	ctx.arge_busaddr = 0;
1355188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag,
1356188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring,
1357188808Sgonzo	    ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1358188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1359188808Sgonzo		device_printf(sc->arge_dev,
1360188808Sgonzo		    "failed to load DMA'able memory for Tx ring\n");
1361188808Sgonzo		goto fail;
1362188808Sgonzo	}
1363188808Sgonzo	sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr;
1364188808Sgonzo
1365188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
1366188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag,
1367188808Sgonzo	    (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK |
1368232628Sray	    BUS_DMA_COHERENT | BUS_DMA_ZERO,
1369232628Sray	    &sc->arge_cdata.arge_rx_ring_map);
1370188808Sgonzo	if (error != 0) {
1371188808Sgonzo		device_printf(sc->arge_dev,
1372188808Sgonzo		    "failed to allocate DMA'able memory for Rx ring\n");
1373188808Sgonzo		goto fail;
1374188808Sgonzo	}
1375188808Sgonzo
1376188808Sgonzo	ctx.arge_busaddr = 0;
1377188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag,
1378188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring,
1379188808Sgonzo	    ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1380188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1381188808Sgonzo		device_printf(sc->arge_dev,
1382188808Sgonzo		    "failed to load DMA'able memory for Rx ring\n");
1383188808Sgonzo		goto fail;
1384188808Sgonzo	}
1385188808Sgonzo	sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr;
1386188808Sgonzo
1387188808Sgonzo	/* Create DMA maps for Tx buffers. */
1388188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1389188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
1390188808Sgonzo		txd->tx_m = NULL;
1391188808Sgonzo		txd->tx_dmamap = NULL;
1392188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0,
1393188808Sgonzo		    &txd->tx_dmamap);
1394188808Sgonzo		if (error != 0) {
1395188808Sgonzo			device_printf(sc->arge_dev,
1396188808Sgonzo			    "failed to create Tx dmamap\n");
1397188808Sgonzo			goto fail;
1398188808Sgonzo		}
1399188808Sgonzo	}
1400188808Sgonzo	/* Create DMA maps for Rx buffers. */
1401188808Sgonzo	if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
1402188808Sgonzo	    &sc->arge_cdata.arge_rx_sparemap)) != 0) {
1403188808Sgonzo		device_printf(sc->arge_dev,
1404188808Sgonzo		    "failed to create spare Rx dmamap\n");
1405188808Sgonzo		goto fail;
1406188808Sgonzo	}
1407188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1408188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
1409188808Sgonzo		rxd->rx_m = NULL;
1410188808Sgonzo		rxd->rx_dmamap = NULL;
1411188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
1412188808Sgonzo		    &rxd->rx_dmamap);
1413188808Sgonzo		if (error != 0) {
1414188808Sgonzo			device_printf(sc->arge_dev,
1415188808Sgonzo			    "failed to create Rx dmamap\n");
1416188808Sgonzo			goto fail;
1417188808Sgonzo		}
1418188808Sgonzo	}
1419188808Sgonzo
1420188808Sgonzofail:
1421188808Sgonzo	return (error);
1422188808Sgonzo}
1423188808Sgonzo
1424188808Sgonzostatic void
1425188808Sgonzoarge_dma_free(struct arge_softc *sc)
1426188808Sgonzo{
1427188808Sgonzo	struct arge_txdesc	*txd;
1428188808Sgonzo	struct arge_rxdesc	*rxd;
1429188808Sgonzo	int			i;
1430188808Sgonzo
1431188808Sgonzo	/* Tx ring. */
1432188808Sgonzo	if (sc->arge_cdata.arge_tx_ring_tag) {
1433188808Sgonzo		if (sc->arge_cdata.arge_tx_ring_map)
1434188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag,
1435188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
1436188808Sgonzo		if (sc->arge_cdata.arge_tx_ring_map &&
1437188808Sgonzo		    sc->arge_rdata.arge_tx_ring)
1438188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag,
1439188808Sgonzo			    sc->arge_rdata.arge_tx_ring,
1440188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
1441188808Sgonzo		sc->arge_rdata.arge_tx_ring = NULL;
1442188808Sgonzo		sc->arge_cdata.arge_tx_ring_map = NULL;
1443188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag);
1444188808Sgonzo		sc->arge_cdata.arge_tx_ring_tag = NULL;
1445188808Sgonzo	}
1446188808Sgonzo	/* Rx ring. */
1447188808Sgonzo	if (sc->arge_cdata.arge_rx_ring_tag) {
1448188808Sgonzo		if (sc->arge_cdata.arge_rx_ring_map)
1449188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag,
1450188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
1451188808Sgonzo		if (sc->arge_cdata.arge_rx_ring_map &&
1452188808Sgonzo		    sc->arge_rdata.arge_rx_ring)
1453188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag,
1454188808Sgonzo			    sc->arge_rdata.arge_rx_ring,
1455188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
1456188808Sgonzo		sc->arge_rdata.arge_rx_ring = NULL;
1457188808Sgonzo		sc->arge_cdata.arge_rx_ring_map = NULL;
1458188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag);
1459188808Sgonzo		sc->arge_cdata.arge_rx_ring_tag = NULL;
1460188808Sgonzo	}
1461188808Sgonzo	/* Tx buffers. */
1462188808Sgonzo	if (sc->arge_cdata.arge_tx_tag) {
1463188808Sgonzo		for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1464188808Sgonzo			txd = &sc->arge_cdata.arge_txdesc[i];
1465188808Sgonzo			if (txd->tx_dmamap) {
1466188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag,
1467188808Sgonzo				    txd->tx_dmamap);
1468188808Sgonzo				txd->tx_dmamap = NULL;
1469188808Sgonzo			}
1470188808Sgonzo		}
1471188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag);
1472188808Sgonzo		sc->arge_cdata.arge_tx_tag = NULL;
1473188808Sgonzo	}
1474188808Sgonzo	/* Rx buffers. */
1475188808Sgonzo	if (sc->arge_cdata.arge_rx_tag) {
1476188808Sgonzo		for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1477188808Sgonzo			rxd = &sc->arge_cdata.arge_rxdesc[i];
1478188808Sgonzo			if (rxd->rx_dmamap) {
1479188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
1480188808Sgonzo				    rxd->rx_dmamap);
1481188808Sgonzo				rxd->rx_dmamap = NULL;
1482188808Sgonzo			}
1483188808Sgonzo		}
1484188808Sgonzo		if (sc->arge_cdata.arge_rx_sparemap) {
1485188808Sgonzo			bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
1486188808Sgonzo			    sc->arge_cdata.arge_rx_sparemap);
1487188808Sgonzo			sc->arge_cdata.arge_rx_sparemap = 0;
1488188808Sgonzo		}
1489188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag);
1490188808Sgonzo		sc->arge_cdata.arge_rx_tag = NULL;
1491188808Sgonzo	}
1492188808Sgonzo
1493188808Sgonzo	if (sc->arge_cdata.arge_parent_tag) {
1494188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag);
1495188808Sgonzo		sc->arge_cdata.arge_parent_tag = NULL;
1496188808Sgonzo	}
1497188808Sgonzo}
1498188808Sgonzo
1499188808Sgonzo/*
1500188808Sgonzo * Initialize the transmit descriptors.
1501188808Sgonzo */
1502188808Sgonzostatic int
1503188808Sgonzoarge_tx_ring_init(struct arge_softc *sc)
1504188808Sgonzo{
1505188808Sgonzo	struct arge_ring_data	*rd;
1506188808Sgonzo	struct arge_txdesc	*txd;
1507188808Sgonzo	bus_addr_t		addr;
1508188808Sgonzo	int			i;
1509188808Sgonzo
1510188808Sgonzo	sc->arge_cdata.arge_tx_prod = 0;
1511188808Sgonzo	sc->arge_cdata.arge_tx_cons = 0;
1512188808Sgonzo	sc->arge_cdata.arge_tx_cnt = 0;
1513188808Sgonzo
1514188808Sgonzo	rd = &sc->arge_rdata;
1515188808Sgonzo	bzero(rd->arge_tx_ring, sizeof(rd->arge_tx_ring));
1516188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1517188808Sgonzo		if (i == ARGE_TX_RING_COUNT - 1)
1518188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, 0);
1519188808Sgonzo		else
1520188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, i + 1);
1521188808Sgonzo		rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY;
1522188808Sgonzo		rd->arge_tx_ring[i].next_desc = addr;
1523188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
1524188808Sgonzo		txd->tx_m = NULL;
1525188808Sgonzo	}
1526188808Sgonzo
1527188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1528188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1529188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1530188808Sgonzo
1531188808Sgonzo	return (0);
1532188808Sgonzo}
1533188808Sgonzo
1534188808Sgonzo/*
1535188808Sgonzo * Initialize the RX descriptors and allocate mbufs for them. Note that
1536188808Sgonzo * we arrange the descriptors in a closed ring, so that the last descriptor
1537188808Sgonzo * points back to the first.
1538188808Sgonzo */
1539188808Sgonzostatic int
1540188808Sgonzoarge_rx_ring_init(struct arge_softc *sc)
1541188808Sgonzo{
1542188808Sgonzo	struct arge_ring_data	*rd;
1543188808Sgonzo	struct arge_rxdesc	*rxd;
1544188808Sgonzo	bus_addr_t		addr;
1545188808Sgonzo	int			i;
1546188808Sgonzo
1547188808Sgonzo	sc->arge_cdata.arge_rx_cons = 0;
1548188808Sgonzo
1549188808Sgonzo	rd = &sc->arge_rdata;
1550188808Sgonzo	bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring));
1551188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1552188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
1553232912Sadrian		if (rxd->rx_m != NULL) {
1554232912Sadrian			device_printf(sc->arge_dev,
1555232912Sadrian			    "%s: ring[%d] rx_m wasn't free?\n",
1556232912Sadrian			    __func__,
1557232912Sadrian			    i);
1558232912Sadrian		}
1559188808Sgonzo		rxd->rx_m = NULL;
1560188808Sgonzo		rxd->desc = &rd->arge_rx_ring[i];
1561188808Sgonzo		if (i == ARGE_RX_RING_COUNT - 1)
1562188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, 0);
1563188808Sgonzo		else
1564188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, i + 1);
1565188808Sgonzo		rd->arge_rx_ring[i].next_desc = addr;
1566192783Sgonzo		if (arge_newbuf(sc, i) != 0) {
1567188808Sgonzo			return (ENOBUFS);
1568192783Sgonzo		}
1569188808Sgonzo	}
1570188808Sgonzo
1571188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1572188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
1573195434Sgonzo	    BUS_DMASYNC_PREWRITE);
1574188808Sgonzo
1575188808Sgonzo	return (0);
1576188808Sgonzo}
1577188808Sgonzo
1578188808Sgonzo/*
1579232912Sadrian * Free all the buffers in the RX ring.
1580232912Sadrian *
1581232912Sadrian * TODO: ensure that DMA is disabled and no pending DMA
1582232912Sadrian * is lurking in the FIFO.
1583232912Sadrian */
1584232912Sadrianstatic void
1585232912Sadrianarge_rx_ring_free(struct arge_softc *sc)
1586232912Sadrian{
1587232912Sadrian	int i;
1588232912Sadrian	struct arge_rxdesc	*rxd;
1589232912Sadrian
1590232912Sadrian	ARGE_LOCK_ASSERT(sc);
1591232912Sadrian
1592232912Sadrian	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1593232912Sadrian		rxd = &sc->arge_cdata.arge_rxdesc[i];
1594232912Sadrian		/* Unmap the mbuf */
1595232912Sadrian		if (rxd->rx_m != NULL) {
1596232912Sadrian			bus_dmamap_unload(sc->arge_cdata.arge_rx_tag,
1597232912Sadrian			    rxd->rx_dmamap);
1598232912Sadrian			m_free(rxd->rx_m);
1599232912Sadrian			rxd->rx_m = NULL;
1600232912Sadrian		}
1601232912Sadrian	}
1602232912Sadrian}
1603232912Sadrian
1604232912Sadrian/*
1605188808Sgonzo * Initialize an RX descriptor and attach an MBUF cluster.
1606188808Sgonzo */
1607188808Sgonzostatic int
1608188808Sgonzoarge_newbuf(struct arge_softc *sc, int idx)
1609188808Sgonzo{
1610188808Sgonzo	struct arge_desc		*desc;
1611188808Sgonzo	struct arge_rxdesc	*rxd;
1612188808Sgonzo	struct mbuf		*m;
1613188808Sgonzo	bus_dma_segment_t	segs[1];
1614188808Sgonzo	bus_dmamap_t		map;
1615188808Sgonzo	int			nsegs;
1616188808Sgonzo
1617188808Sgonzo	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1618188808Sgonzo	if (m == NULL)
1619188808Sgonzo		return (ENOBUFS);
1620188808Sgonzo	m->m_len = m->m_pkthdr.len = MCLBYTES;
1621188808Sgonzo	m_adj(m, sizeof(uint64_t));
1622188808Sgonzo
1623188808Sgonzo	if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag,
1624188808Sgonzo	    sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) {
1625188808Sgonzo		m_freem(m);
1626188808Sgonzo		return (ENOBUFS);
1627188808Sgonzo	}
1628188808Sgonzo	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1629188808Sgonzo
1630188808Sgonzo	rxd = &sc->arge_cdata.arge_rxdesc[idx];
1631188808Sgonzo	if (rxd->rx_m != NULL) {
1632188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap);
1633188808Sgonzo	}
1634188808Sgonzo	map = rxd->rx_dmamap;
1635188808Sgonzo	rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap;
1636188808Sgonzo	sc->arge_cdata.arge_rx_sparemap = map;
1637188808Sgonzo	rxd->rx_m = m;
1638188808Sgonzo	desc = rxd->desc;
1639192783Sgonzo	if (segs[0].ds_addr & 3)
1640192783Sgonzo		panic("RX packet address unaligned");
1641188808Sgonzo	desc->packet_addr = segs[0].ds_addr;
1642192783Sgonzo	desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len);
1643188808Sgonzo
1644195434Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1645195434Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
1646195434Sgonzo	    BUS_DMASYNC_PREWRITE);
1647195434Sgonzo
1648188808Sgonzo	return (0);
1649188808Sgonzo}
1650188808Sgonzo
1651188808Sgonzostatic __inline void
1652188808Sgonzoarge_fixup_rx(struct mbuf *m)
1653188808Sgonzo{
1654198933Sgonzo	int		i;
1655198933Sgonzo	uint16_t	*src, *dst;
1656188808Sgonzo
1657188808Sgonzo	src = mtod(m, uint16_t *);
1658188808Sgonzo	dst = src - 1;
1659188808Sgonzo
1660195434Sgonzo	for (i = 0; i < m->m_len / sizeof(uint16_t); i++) {
1661188808Sgonzo		*dst++ = *src++;
1662195434Sgonzo	}
1663188808Sgonzo
1664195434Sgonzo	if (m->m_len % sizeof(uint16_t))
1665195434Sgonzo		*(uint8_t *)dst = *(uint8_t *)src;
1666195434Sgonzo
1667188808Sgonzo	m->m_data -= ETHER_ALIGN;
1668188808Sgonzo}
1669188808Sgonzo
1670192783Sgonzo#ifdef DEVICE_POLLING
1671198667Sgonzostatic int
1672192783Sgonzoarge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1673192783Sgonzo{
1674192783Sgonzo	struct arge_softc *sc = ifp->if_softc;
1675198667Sgonzo	int rx_npkts = 0;
1676188808Sgonzo
1677198933Sgonzo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1678192783Sgonzo		ARGE_LOCK(sc);
1679192783Sgonzo		arge_tx_locked(sc);
1680198667Sgonzo		rx_npkts = arge_rx_locked(sc);
1681192783Sgonzo		ARGE_UNLOCK(sc);
1682198933Sgonzo	}
1683198667Sgonzo
1684198667Sgonzo	return (rx_npkts);
1685192783Sgonzo}
1686192783Sgonzo#endif /* DEVICE_POLLING */
1687192783Sgonzo
1688192783Sgonzo
1689188808Sgonzostatic void
1690188808Sgonzoarge_tx_locked(struct arge_softc *sc)
1691188808Sgonzo{
1692188808Sgonzo	struct arge_txdesc	*txd;
1693188808Sgonzo	struct arge_desc	*cur_tx;
1694188808Sgonzo	struct ifnet		*ifp;
1695188808Sgonzo	uint32_t		ctrl;
1696188808Sgonzo	int			cons, prod;
1697188808Sgonzo
1698188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1699188808Sgonzo
1700188808Sgonzo	cons = sc->arge_cdata.arge_tx_cons;
1701188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
1702220356Sadrian
1703232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: cons=%d, prod=%d\n", __func__, cons,
1704232628Sray	    prod);
1705220356Sadrian
1706188808Sgonzo	if (cons == prod)
1707188808Sgonzo		return;
1708188808Sgonzo
1709188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1710188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1711188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1712188808Sgonzo
1713188808Sgonzo	ifp = sc->arge_ifp;
1714188808Sgonzo	/*
1715188808Sgonzo	 * Go through our tx list and free mbufs for those
1716188808Sgonzo	 * frames that have been transmitted.
1717188808Sgonzo	 */
1718188808Sgonzo	for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) {
1719188808Sgonzo		cur_tx = &sc->arge_rdata.arge_tx_ring[cons];
1720188808Sgonzo		ctrl = cur_tx->packet_ctrl;
1721188808Sgonzo		/* Check if descriptor has "finished" flag */
1722188808Sgonzo		if ((ctrl & ARGE_DESC_EMPTY) == 0)
1723188808Sgonzo			break;
1724188808Sgonzo
1725188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
1726188808Sgonzo
1727188808Sgonzo		sc->arge_cdata.arge_tx_cnt--;
1728188808Sgonzo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1729188808Sgonzo
1730188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[cons];
1731188808Sgonzo
1732188808Sgonzo		ifp->if_opackets++;
1733188808Sgonzo
1734188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
1735188808Sgonzo		    BUS_DMASYNC_POSTWRITE);
1736188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
1737188808Sgonzo
1738188808Sgonzo		/* Free only if it's first descriptor in list */
1739188808Sgonzo		if (txd->tx_m)
1740188808Sgonzo			m_freem(txd->tx_m);
1741188808Sgonzo		txd->tx_m = NULL;
1742188808Sgonzo
1743188808Sgonzo		/* reset descriptor */
1744188808Sgonzo		cur_tx->packet_addr = 0;
1745188808Sgonzo	}
1746188808Sgonzo
1747188808Sgonzo	sc->arge_cdata.arge_tx_cons = cons;
1748188808Sgonzo
1749188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1750188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE);
1751188808Sgonzo}
1752188808Sgonzo
1753188808Sgonzo
1754198667Sgonzostatic int
1755188808Sgonzoarge_rx_locked(struct arge_softc *sc)
1756188808Sgonzo{
1757188808Sgonzo	struct arge_rxdesc	*rxd;
1758188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
1759192783Sgonzo	int			cons, prog, packet_len, i;
1760188808Sgonzo	struct arge_desc	*cur_rx;
1761188808Sgonzo	struct mbuf		*m;
1762198667Sgonzo	int			rx_npkts = 0;
1763188808Sgonzo
1764188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1765188808Sgonzo
1766188808Sgonzo	cons = sc->arge_cdata.arge_rx_cons;
1767188808Sgonzo
1768188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1769188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
1770188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1771188808Sgonzo
1772232627Sray	for (prog = 0; prog < ARGE_RX_RING_COUNT;
1773188808Sgonzo	    ARGE_INC(cons, ARGE_RX_RING_COUNT)) {
1774188808Sgonzo		cur_rx = &sc->arge_rdata.arge_rx_ring[cons];
1775188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[cons];
1776188808Sgonzo		m = rxd->rx_m;
1777188808Sgonzo
1778188808Sgonzo		if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0)
1779232627Sray		       break;
1780188808Sgonzo
1781188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
1782188808Sgonzo
1783188808Sgonzo		prog++;
1784188808Sgonzo
1785188808Sgonzo		packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl);
1786188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
1787195434Sgonzo		    BUS_DMASYNC_POSTREAD);
1788188808Sgonzo		m = rxd->rx_m;
1789188808Sgonzo
1790188808Sgonzo		arge_fixup_rx(m);
1791188808Sgonzo		m->m_pkthdr.rcvif = ifp;
1792188808Sgonzo		/* Skip 4 bytes of CRC */
1793188808Sgonzo		m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
1794188808Sgonzo		ifp->if_ipackets++;
1795198667Sgonzo		rx_npkts++;
1796188808Sgonzo
1797188808Sgonzo		ARGE_UNLOCK(sc);
1798188808Sgonzo		(*ifp->if_input)(ifp, m);
1799188808Sgonzo		ARGE_LOCK(sc);
1800192783Sgonzo		cur_rx->packet_addr = 0;
1801192783Sgonzo	}
1802188808Sgonzo
1803192783Sgonzo	if (prog > 0) {
1804192783Sgonzo
1805192783Sgonzo		i = sc->arge_cdata.arge_rx_cons;
1806192783Sgonzo		for (; prog > 0 ; prog--) {
1807192783Sgonzo			if (arge_newbuf(sc, i) != 0) {
1808232627Sray				device_printf(sc->arge_dev,
1809192783Sgonzo				    "Failed to allocate buffer\n");
1810192783Sgonzo				break;
1811192783Sgonzo			}
1812192783Sgonzo			ARGE_INC(i, ARGE_RX_RING_COUNT);
1813188808Sgonzo		}
1814188808Sgonzo
1815188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
1816188808Sgonzo		    sc->arge_cdata.arge_rx_ring_map,
1817195434Sgonzo		    BUS_DMASYNC_PREWRITE);
1818188808Sgonzo
1819188808Sgonzo		sc->arge_cdata.arge_rx_cons = cons;
1820188808Sgonzo	}
1821198667Sgonzo
1822198667Sgonzo	return (rx_npkts);
1823188808Sgonzo}
1824188808Sgonzo
1825188808Sgonzostatic int
1826188808Sgonzoarge_intr_filter(void *arg)
1827188808Sgonzo{
1828188808Sgonzo	struct arge_softc	*sc = arg;
1829188808Sgonzo	uint32_t		status, ints;
1830188808Sgonzo
1831188808Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
1832188808Sgonzo	ints = ARGE_READ(sc, AR71XX_DMA_INTR);
1833188808Sgonzo
1834220354Sadrian	ARGEDEBUG(sc, ARGE_DBG_INTR, "int mask(filter) = %b\n", ints,
1835188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
1836188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
1837232627Sray	ARGEDEBUG(sc, ARGE_DBG_INTR, "status(filter) = %b\n", status,
1838188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
1839188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
1840188808Sgonzo
1841188808Sgonzo	if (status & DMA_INTR_ALL) {
1842191644Sgonzo		sc->arge_intr_status |= status;
1843192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1844188808Sgonzo		return (FILTER_SCHEDULE_THREAD);
1845232627Sray	}
1846188808Sgonzo
1847188808Sgonzo	sc->arge_intr_status = 0;
1848188808Sgonzo	return (FILTER_STRAY);
1849188808Sgonzo}
1850188808Sgonzo
1851188808Sgonzostatic void
1852188808Sgonzoarge_intr(void *arg)
1853188808Sgonzo{
1854188808Sgonzo	struct arge_softc	*sc = arg;
1855188808Sgonzo	uint32_t		status;
1856220356Sadrian	struct ifnet		*ifp = sc->arge_ifp;
1857188808Sgonzo
1858192783Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
1859192783Sgonzo	status |= sc->arge_intr_status;
1860188808Sgonzo
1861232627Sray	ARGEDEBUG(sc, ARGE_DBG_INTR, "int status(intr) = %b\n", status,
1862188808Sgonzo	    "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD"
1863188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
1864188808Sgonzo
1865232627Sray	/*
1866232627Sray	 * Is it our interrupt at all?
1867188808Sgonzo	 */
1868188808Sgonzo	if (status == 0)
1869188808Sgonzo		return;
1870188808Sgonzo
1871188808Sgonzo	if (status & DMA_INTR_RX_BUS_ERROR) {
1872188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR);
1873188808Sgonzo		device_printf(sc->arge_dev, "RX bus error");
1874188808Sgonzo		return;
1875188808Sgonzo	}
1876188808Sgonzo
1877188808Sgonzo	if (status & DMA_INTR_TX_BUS_ERROR) {
1878188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR);
1879188808Sgonzo		device_printf(sc->arge_dev, "TX bus error");
1880188808Sgonzo		return;
1881188808Sgonzo	}
1882188808Sgonzo
1883192783Sgonzo	ARGE_LOCK(sc);
1884188808Sgonzo
1885192783Sgonzo	if (status & DMA_INTR_RX_PKT_RCVD)
1886192783Sgonzo		arge_rx_locked(sc);
1887188808Sgonzo
1888232627Sray	/*
1889232627Sray	 * RX overrun disables the receiver.
1890232627Sray	 * Clear indication and re-enable rx.
1891192783Sgonzo	 */
1892192783Sgonzo	if ( status & DMA_INTR_RX_OVERFLOW) {
1893192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW);
1894192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
1895220356Sadrian		sc->stats.rx_overflow++;
1896192783Sgonzo	}
1897188808Sgonzo
1898192783Sgonzo	if (status & DMA_INTR_TX_PKT_SENT)
1899192783Sgonzo		arge_tx_locked(sc);
1900232627Sray	/*
1901232627Sray	 * Underrun turns off TX. Clear underrun indication.
1902232627Sray	 * If there's anything left in the ring, reactivate the tx.
1903192783Sgonzo	 */
1904192569Sdwhite	if (status & DMA_INTR_TX_UNDERRUN) {
1905192569Sdwhite		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN);
1906220356Sadrian		sc->stats.tx_underflow++;
1907232628Sray		ARGEDEBUG(sc, ARGE_DBG_TX, "%s: TX underrun; tx_cnt=%d\n",
1908232628Sray		    __func__, sc->arge_cdata.arge_tx_cnt);
1909219590Sadrian		if (sc->arge_cdata.arge_tx_cnt > 0 ) {
1910232627Sray			ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL,
1911192783Sgonzo			    DMA_TX_CONTROL_EN);
1912192783Sgonzo		}
1913192569Sdwhite	}
1914192569Sdwhite
1915192946Sgonzo	/*
1916220357Sadrian	 * If we've finished TXing and there's space for more packets
1917220357Sadrian	 * to be queued for TX, do so. Otherwise we may end up in a
1918220357Sadrian	 * situation where the interface send queue was filled
1919220357Sadrian	 * whilst the hardware queue was full, then the hardware
1920220357Sadrian	 * queue was drained by the interface send queue wasn't,
1921220357Sadrian	 * and thus if_start() is never called to kick-start
1922220357Sadrian	 * the send process (and all subsequent packets are simply
1923220357Sadrian	 * discarded.
1924220357Sadrian	 *
1925220357Sadrian	 * XXX TODO: make sure that the hardware deals nicely
1926220357Sadrian	 * with the possibility of the queue being enabled above
1927220357Sadrian	 * after a TX underrun, then having the hardware queue added
1928220357Sadrian	 * to below.
1929220357Sadrian	 */
1930220357Sadrian	if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) &&
1931220357Sadrian	    (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
1932220357Sadrian		if (!IFQ_IS_EMPTY(&ifp->if_snd))
1933220357Sadrian			arge_start_locked(ifp);
1934220357Sadrian	}
1935220357Sadrian
1936220357Sadrian	/*
1937192946Sgonzo	 * We handled all bits, clear status
1938192946Sgonzo	 */
1939192946Sgonzo	sc->arge_intr_status = 0;
1940188808Sgonzo	ARGE_UNLOCK(sc);
1941192783Sgonzo	/*
1942232627Sray	 * re-enable all interrupts
1943192783Sgonzo	 */
1944192783Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1945188808Sgonzo}
1946188808Sgonzo
1947192783Sgonzo
1948188808Sgonzostatic void
1949188808Sgonzoarge_tick(void *xsc)
1950188808Sgonzo{
1951188808Sgonzo	struct arge_softc	*sc = xsc;
1952188808Sgonzo	struct mii_data		*mii;
1953188808Sgonzo
1954188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1955188808Sgonzo
1956199234Sgonzo	if (sc->arge_miibus) {
1957199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
1958199234Sgonzo		mii_tick(mii);
1959199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
1960199234Sgonzo	}
1961188808Sgonzo}
1962199234Sgonzo
1963199234Sgonzoint
1964199234Sgonzoarge_multiphy_mediachange(struct ifnet *ifp)
1965199234Sgonzo{
1966199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
1967199234Sgonzo	struct ifmedia *ifm = &sc->arge_ifmedia;
1968199234Sgonzo	struct ifmedia_entry *ife = ifm->ifm_cur;
1969199234Sgonzo
1970199234Sgonzo	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1971199234Sgonzo		return (EINVAL);
1972199234Sgonzo
1973199234Sgonzo	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
1974232627Sray		device_printf(sc->arge_dev,
1975199234Sgonzo		    "AUTO is not supported for multiphy MAC");
1976199234Sgonzo		return (EINVAL);
1977199234Sgonzo	}
1978199234Sgonzo
1979199234Sgonzo	/*
1980199234Sgonzo	 * Ignore everything
1981199234Sgonzo	 */
1982199234Sgonzo	return (0);
1983199234Sgonzo}
1984199234Sgonzo
1985199234Sgonzovoid
1986199234Sgonzoarge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1987199234Sgonzo{
1988199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
1989199234Sgonzo
1990199234Sgonzo	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
1991232627Sray	ifmr->ifm_active = IFM_ETHER | sc->arge_media_type |
1992199234Sgonzo	    sc->arge_duplex_mode;
1993199234Sgonzo}
1994199234Sgonzo
1995