if_arge.c revision 290215
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 290215 2015-10-30 23:18:02Z 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>
44257284Sglebius#include <sys/lock.h>
45188808Sgonzo#include <sys/mbuf.h>
46188808Sgonzo#include <sys/malloc.h>
47257284Sglebius#include <sys/mutex.h>
48188808Sgonzo#include <sys/kernel.h>
49188808Sgonzo#include <sys/module.h>
50188808Sgonzo#include <sys/socket.h>
51188808Sgonzo#include <sys/taskqueue.h>
52209802Sadrian#include <sys/sysctl.h>
53188808Sgonzo
54188808Sgonzo#include <net/if.h>
55257284Sglebius#include <net/if_var.h>
56257284Sglebius#include <net/if_media.h>
57188808Sgonzo#include <net/ethernet.h>
58188808Sgonzo#include <net/if_types.h>
59188808Sgonzo
60188808Sgonzo#include <net/bpf.h>
61188808Sgonzo
62188808Sgonzo#include <machine/bus.h>
63188808Sgonzo#include <machine/cache.h>
64188808Sgonzo#include <machine/resource.h>
65188808Sgonzo#include <vm/vm_param.h>
66188808Sgonzo#include <vm/vm.h>
67188808Sgonzo#include <vm/pmap.h>
68188808Sgonzo#include <machine/pmap.h>
69188808Sgonzo#include <sys/bus.h>
70188808Sgonzo#include <sys/rman.h>
71188808Sgonzo
72188808Sgonzo#include <dev/mii/mii.h>
73188808Sgonzo#include <dev/mii/miivar.h>
74188808Sgonzo
75188808Sgonzo#include <dev/pci/pcireg.h>
76188808Sgonzo#include <dev/pci/pcivar.h>
77188808Sgonzo
78234862Sadrian#include "opt_arge.h"
79234862Sadrian
80234862Sadrian#if defined(ARGE_MDIO)
81234862Sadrian#include <dev/etherswitch/mdio.h>
82234862Sadrian#include <dev/etherswitch/miiproxy.h>
83234862Sadrian#include "mdio_if.h"
84234862Sadrian#endif
85234862Sadrian
86234862Sadrian
87188808SgonzoMODULE_DEPEND(arge, ether, 1, 1, 1);
88188808SgonzoMODULE_DEPEND(arge, miibus, 1, 1, 1);
89234862SadrianMODULE_VERSION(arge, 1);
90188808Sgonzo
91188808Sgonzo#include "miibus_if.h"
92188808Sgonzo
93280798Sadrian#include <net/ethernet.h>
94280798Sadrian
95188808Sgonzo#include <mips/atheros/ar71xxreg.h>
96256575Sadrian#include <mips/atheros/ar934xreg.h>	/* XXX tsk! */
97279510Sadrian#include <mips/atheros/qca955xreg.h>	/* XXX tsk! */
98188808Sgonzo#include <mips/atheros/if_argevar.h>
99219589Sadrian#include <mips/atheros/ar71xx_setup.h>
100211477Sadrian#include <mips/atheros/ar71xx_cpudef.h>
101280124Sadrian#include <mips/atheros/ar71xx_macaddr.h>
102188808Sgonzo
103220354Sadriantypedef enum {
104220354Sadrian	ARGE_DBG_MII 	=	0x00000001,
105220356Sadrian	ARGE_DBG_INTR	=	0x00000002,
106220356Sadrian	ARGE_DBG_TX	=	0x00000004,
107220356Sadrian	ARGE_DBG_RX	=	0x00000008,
108220356Sadrian	ARGE_DBG_ERR	=	0x00000010,
109220356Sadrian	ARGE_DBG_RESET	=	0x00000020,
110234919Sadrian	ARGE_DBG_PLL	=	0x00000040,
111220354Sadrian} arge_debug_flags;
112220354Sadrian
113234910Sadrianstatic const char * arge_miicfg_str[] = {
114234910Sadrian	"NONE",
115234910Sadrian	"GMII",
116234910Sadrian	"MII",
117234910Sadrian	"RGMII",
118279510Sadrian	"RMII",
119279510Sadrian	"SGMII"
120234910Sadrian};
121234910Sadrian
122188808Sgonzo#ifdef ARGE_DEBUG
123220354Sadrian#define	ARGEDEBUG(_sc, _m, ...) 					\
124220354Sadrian	do {								\
125220354Sadrian		if ((_m) & (_sc)->arge_debug)				\
126220354Sadrian			device_printf((_sc)->arge_dev, __VA_ARGS__);	\
127220354Sadrian	} while (0)
128188808Sgonzo#else
129220354Sadrian#define	ARGEDEBUG(_sc, _m, ...)
130188808Sgonzo#endif
131188808Sgonzo
132188808Sgonzostatic int arge_attach(device_t);
133188808Sgonzostatic int arge_detach(device_t);
134188808Sgonzostatic void arge_flush_ddr(struct arge_softc *);
135188808Sgonzostatic int arge_ifmedia_upd(struct ifnet *);
136188808Sgonzostatic void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
137188808Sgonzostatic int arge_ioctl(struct ifnet *, u_long, caddr_t);
138188808Sgonzostatic void arge_init(void *);
139188808Sgonzostatic void arge_init_locked(struct arge_softc *);
140188808Sgonzostatic void arge_link_task(void *, int);
141232914Sadrianstatic void arge_update_link_locked(struct arge_softc *sc);
142199234Sgonzostatic void arge_set_pll(struct arge_softc *, int, int);
143188808Sgonzostatic int arge_miibus_readreg(device_t, int, int);
144188808Sgonzostatic void arge_miibus_statchg(device_t);
145188808Sgonzostatic int arge_miibus_writereg(device_t, int, int, int);
146188808Sgonzostatic int arge_probe(device_t);
147188808Sgonzostatic void arge_reset_dma(struct arge_softc *);
148188808Sgonzostatic int arge_resume(device_t);
149188808Sgonzostatic int arge_rx_ring_init(struct arge_softc *);
150232912Sadrianstatic void arge_rx_ring_free(struct arge_softc *sc);
151188808Sgonzostatic int arge_tx_ring_init(struct arge_softc *);
152255300Sloosstatic void arge_tx_ring_free(struct arge_softc *);
153192821Sgonzo#ifdef DEVICE_POLLING
154198667Sgonzostatic int arge_poll(struct ifnet *, enum poll_cmd, int);
155192821Sgonzo#endif
156194059Sgonzostatic int arge_shutdown(device_t);
157188808Sgonzostatic void arge_start(struct ifnet *);
158188808Sgonzostatic void arge_start_locked(struct ifnet *);
159188808Sgonzostatic void arge_stop(struct arge_softc *);
160188808Sgonzostatic int arge_suspend(device_t);
161188808Sgonzo
162198667Sgonzostatic int arge_rx_locked(struct arge_softc *);
163188808Sgonzostatic void arge_tx_locked(struct arge_softc *);
164188808Sgonzostatic void arge_intr(void *);
165188808Sgonzostatic int arge_intr_filter(void *);
166188808Sgonzostatic void arge_tick(void *);
167188808Sgonzo
168234862Sadrianstatic void arge_hinted_child(device_t bus, const char *dname, int dunit);
169234862Sadrian
170199234Sgonzo/*
171199234Sgonzo * ifmedia callbacks for multiPHY MAC
172199234Sgonzo */
173199234Sgonzovoid arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *);
174199234Sgonzoint arge_multiphy_mediachange(struct ifnet *);
175199234Sgonzo
176188808Sgonzostatic void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int);
177188808Sgonzostatic int arge_dma_alloc(struct arge_softc *);
178188808Sgonzostatic void arge_dma_free(struct arge_softc *);
179188808Sgonzostatic int arge_newbuf(struct arge_softc *, int);
180188808Sgonzostatic __inline void arge_fixup_rx(struct mbuf *);
181188808Sgonzo
182188808Sgonzostatic device_method_t arge_methods[] = {
183188808Sgonzo	/* Device interface */
184188808Sgonzo	DEVMETHOD(device_probe,		arge_probe),
185188808Sgonzo	DEVMETHOD(device_attach,	arge_attach),
186188808Sgonzo	DEVMETHOD(device_detach,	arge_detach),
187188808Sgonzo	DEVMETHOD(device_suspend,	arge_suspend),
188188808Sgonzo	DEVMETHOD(device_resume,	arge_resume),
189188808Sgonzo	DEVMETHOD(device_shutdown,	arge_shutdown),
190188808Sgonzo
191188808Sgonzo	/* MII interface */
192188808Sgonzo	DEVMETHOD(miibus_readreg,	arge_miibus_readreg),
193188808Sgonzo	DEVMETHOD(miibus_writereg,	arge_miibus_writereg),
194188808Sgonzo	DEVMETHOD(miibus_statchg,	arge_miibus_statchg),
195188808Sgonzo
196234862Sadrian	/* bus interface */
197234862Sadrian	DEVMETHOD(bus_add_child,	device_add_child_ordered),
198234862Sadrian	DEVMETHOD(bus_hinted_child,	arge_hinted_child),
199234862Sadrian
200227843Smarius	DEVMETHOD_END
201188808Sgonzo};
202188808Sgonzo
203188808Sgonzostatic driver_t arge_driver = {
204188808Sgonzo	"arge",
205188808Sgonzo	arge_methods,
206188808Sgonzo	sizeof(struct arge_softc)
207188808Sgonzo};
208188808Sgonzo
209188808Sgonzostatic devclass_t arge_devclass;
210188808Sgonzo
211188808SgonzoDRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0);
212188808SgonzoDRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0);
213188808Sgonzo
214234862Sadrian#if defined(ARGE_MDIO)
215234862Sadrianstatic int argemdio_probe(device_t);
216234862Sadrianstatic int argemdio_attach(device_t);
217234862Sadrianstatic int argemdio_detach(device_t);
218234862Sadrian
219188808Sgonzo/*
220234862Sadrian * Declare an additional, separate driver for accessing the MDIO bus.
221234862Sadrian */
222234862Sadrianstatic device_method_t argemdio_methods[] = {
223234862Sadrian	/* Device interface */
224234862Sadrian	DEVMETHOD(device_probe,		argemdio_probe),
225234862Sadrian	DEVMETHOD(device_attach,	argemdio_attach),
226234862Sadrian	DEVMETHOD(device_detach,	argemdio_detach),
227234862Sadrian
228234862Sadrian	/* bus interface */
229234862Sadrian	DEVMETHOD(bus_add_child,	device_add_child_ordered),
230234862Sadrian
231234862Sadrian	/* MDIO access */
232234862Sadrian	DEVMETHOD(mdio_readreg,		arge_miibus_readreg),
233234862Sadrian	DEVMETHOD(mdio_writereg,	arge_miibus_writereg),
234234862Sadrian};
235234862Sadrian
236234862SadrianDEFINE_CLASS_0(argemdio, argemdio_driver, argemdio_methods,
237234862Sadrian    sizeof(struct arge_softc));
238234862Sadrianstatic devclass_t argemdio_devclass;
239234862Sadrian
240234862SadrianDRIVER_MODULE(miiproxy, arge, miiproxy_driver, miiproxy_devclass, 0, 0);
241234862SadrianDRIVER_MODULE(argemdio, nexus, argemdio_driver, argemdio_devclass, 0, 0);
242234862SadrianDRIVER_MODULE(mdio, argemdio, mdio_driver, mdio_devclass, 0, 0);
243234862Sadrian#endif
244234862Sadrian
245199038Sgonzostatic struct mtx miibus_mtx;
246199038Sgonzo
247206400SgonzoMTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF);
248199038Sgonzo
249192179Sgonzo/*
250232627Sray * Flushes all
251285121Sadrian *
252285121Sadrian * XXX this needs to be done at interrupt time! Grr!
253188808Sgonzo */
254188808Sgonzostatic void
255188808Sgonzoarge_flush_ddr(struct arge_softc *sc)
256188808Sgonzo{
257285121Sadrian	switch (sc->arge_mac_unit) {
258285121Sadrian	case 0:
259285121Sadrian		ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_GE0);
260285121Sadrian		break;
261285121Sadrian	case 1:
262285121Sadrian		ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_GE1);
263285121Sadrian		break;
264285121Sadrian	default:
265285121Sadrian		device_printf(sc->arge_dev, "%s: unknown unit (%d)\n",
266285121Sadrian		    __func__,
267285121Sadrian		    sc->arge_mac_unit);
268285121Sadrian		break;
269285121Sadrian	}
270188808Sgonzo}
271188808Sgonzo
272232627Sraystatic int
273188808Sgonzoarge_probe(device_t dev)
274188808Sgonzo{
275188808Sgonzo
276188808Sgonzo	device_set_desc(dev, "Atheros AR71xx built-in ethernet interface");
277257338Snwhitehorn	return (BUS_PROBE_NOWILDCARD);
278188808Sgonzo}
279188808Sgonzo
280290090Sadrian#ifdef	ARGE_DEBUG
281209802Sadrianstatic void
282290090Sadrianarge_attach_intr_sysctl(device_t dev, struct sysctl_oid_list *parent)
283290090Sadrian{
284290090Sadrian	struct arge_softc *sc = device_get_softc(dev);
285290090Sadrian	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
286290090Sadrian	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
287290090Sadrian	struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree);
288290090Sadrian	char sn[8];
289290090Sadrian	int i;
290290090Sadrian
291290090Sadrian	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "intr",
292290090Sadrian	    CTLFLAG_RD, NULL, "Interrupt statistics");
293290090Sadrian	child = SYSCTL_CHILDREN(tree);
294290090Sadrian	for (i = 0; i < 32; i++) {
295290090Sadrian		snprintf(sn, sizeof(sn), "%d", i);
296290090Sadrian		SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD,
297290090Sadrian		    &sc->intr_stats.count[i], 0, "");
298290090Sadrian	}
299290090Sadrian}
300290090Sadrian#endif
301290090Sadrian
302290090Sadrianstatic void
303209802Sadrianarge_attach_sysctl(device_t dev)
304209802Sadrian{
305209802Sadrian	struct arge_softc *sc = device_get_softc(dev);
306209802Sadrian	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
307209802Sadrian	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
308209802Sadrian
309220355Sadrian#ifdef	ARGE_DEBUG
310209802Sadrian	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
311209802Sadrian		"debug", CTLFLAG_RW, &sc->arge_debug, 0,
312209802Sadrian		"arge interface debugging flags");
313290090Sadrian	arge_attach_intr_sysctl(dev, SYSCTL_CHILDREN(tree));
314220355Sadrian#endif
315209809Sadrian
316209809Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
317209809Sadrian		"tx_pkts_aligned", CTLFLAG_RW, &sc->stats.tx_pkts_aligned, 0,
318209809Sadrian		"number of TX aligned packets");
319209809Sadrian
320209809Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
321232628Sray		"tx_pkts_unaligned", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned,
322232628Sray		0, "number of TX unaligned packets");
323220354Sadrian
324289476Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
325289476Sadrian		"tx_pkts_unaligned_start", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned_start,
326289476Sadrian		0, "number of TX unaligned packets (start)");
327289476Sadrian
328289476Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
329289476Sadrian		"tx_pkts_unaligned_len", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned_len,
330289476Sadrian		0, "number of TX unaligned packets (len)");
331289476Sadrian
332289476Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
333289476Sadrian		"tx_pkts_nosegs", CTLFLAG_RW, &sc->stats.tx_pkts_nosegs,
334289476Sadrian		0, "number of TX packets fail with no ring slots avail");
335289476Sadrian
336289476Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
337289476Sadrian		"intr_stray_filter", CTLFLAG_RW, &sc->stats.intr_stray,
338289476Sadrian		0, "number of stray interrupts (filter)");
339289476Sadrian
340289476Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
341289476Sadrian		"intr_stray_intr", CTLFLAG_RW, &sc->stats.intr_stray2,
342289476Sadrian		0, "number of stray interrupts (intr)");
343289476Sadrian
344289476Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
345289476Sadrian		"intr_ok", CTLFLAG_RW, &sc->stats.intr_ok,
346289476Sadrian		0, "number of OK interrupts");
347220355Sadrian#ifdef	ARGE_DEBUG
348220355Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_prod",
349220355Sadrian	    CTLFLAG_RW, &sc->arge_cdata.arge_tx_prod, 0, "");
350220355Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cons",
351220355Sadrian	    CTLFLAG_RW, &sc->arge_cdata.arge_tx_cons, 0, "");
352220355Sadrian	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cnt",
353220355Sadrian	    CTLFLAG_RW, &sc->arge_cdata.arge_tx_cnt, 0, "");
354220355Sadrian#endif
355209802Sadrian}
356209802Sadrian
357234862Sadrianstatic void
358234862Sadrianarge_reset_mac(struct arge_softc *sc)
359234862Sadrian{
360234862Sadrian	uint32_t reg;
361256575Sadrian	uint32_t reset_reg;
362234862Sadrian
363279791Sadrian	ARGEDEBUG(sc, ARGE_DBG_RESET, "%s called\n", __func__);
364279791Sadrian
365234862Sadrian	/* Step 1. Soft-reset MAC */
366234862Sadrian	ARGE_SET_BITS(sc, AR71XX_MAC_CFG1, MAC_CFG1_SOFT_RESET);
367234862Sadrian	DELAY(20);
368234862Sadrian
369234862Sadrian	/* Step 2. Punt the MAC core from the central reset register */
370256575Sadrian	/*
371256575Sadrian	 * XXX TODO: migrate this (and other) chip specific stuff into
372256575Sadrian	 * a chipdef method.
373256575Sadrian	 */
374256575Sadrian	if (sc->arge_mac_unit == 0) {
375256575Sadrian		reset_reg = RST_RESET_GE0_MAC;
376256575Sadrian	} else {
377256575Sadrian		reset_reg = RST_RESET_GE1_MAC;
378256575Sadrian	}
379256575Sadrian
380256575Sadrian	/*
381256575Sadrian	 * AR934x (and later) also needs the MDIO block reset.
382279510Sadrian	 * XXX should methodize this!
383256575Sadrian	 */
384256575Sadrian	if (ar71xx_soc == AR71XX_SOC_AR9341 ||
385256575Sadrian	   ar71xx_soc == AR71XX_SOC_AR9342 ||
386256575Sadrian	   ar71xx_soc == AR71XX_SOC_AR9344) {
387256575Sadrian		if (sc->arge_mac_unit == 0) {
388256575Sadrian			reset_reg |= AR934X_RESET_GE0_MDIO;
389256575Sadrian		} else {
390256575Sadrian			reset_reg |= AR934X_RESET_GE1_MDIO;
391256575Sadrian		}
392256575Sadrian	}
393279510Sadrian
394279510Sadrian	if (ar71xx_soc == AR71XX_SOC_QCA9556 ||
395279510Sadrian	   ar71xx_soc == AR71XX_SOC_QCA9558) {
396279510Sadrian		if (sc->arge_mac_unit == 0) {
397279510Sadrian			reset_reg |= QCA955X_RESET_GE0_MDIO;
398279510Sadrian		} else {
399279510Sadrian			reset_reg |= QCA955X_RESET_GE1_MDIO;
400279510Sadrian		}
401279510Sadrian	}
402256575Sadrian	ar71xx_device_stop(reset_reg);
403234862Sadrian	DELAY(100);
404256575Sadrian	ar71xx_device_start(reset_reg);
405234862Sadrian
406234862Sadrian	/* Step 3. Reconfigure MAC block */
407234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_CFG1,
408234862Sadrian		MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE |
409234862Sadrian		MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE);
410234862Sadrian
411234862Sadrian	reg = ARGE_READ(sc, AR71XX_MAC_CFG2);
412234862Sadrian	reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ;
413234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg);
414234862Sadrian
415234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536);
416234862Sadrian}
417234862Sadrian
418256575Sadrian/*
419256648Sadrian * These values map to the divisor values programmed into
420256648Sadrian * AR71XX_MAC_MII_CFG.
421256648Sadrian *
422256648Sadrian * The index of each value corresponds to the divisor section
423256648Sadrian * value in AR71XX_MAC_MII_CFG (ie, table[0] means '0' in
424256648Sadrian * AR71XX_MAC_MII_CFG, table[1] means '1', etc.)
425256648Sadrian */
426256648Sadrianstatic const uint32_t ar71xx_mdio_div_table[] = {
427256648Sadrian	4, 4, 6, 8, 10, 14, 20, 28,
428256648Sadrian};
429256648Sadrian
430256648Sadrianstatic const uint32_t ar7240_mdio_div_table[] = {
431256648Sadrian	2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
432256648Sadrian};
433256648Sadrian
434256648Sadrianstatic const uint32_t ar933x_mdio_div_table[] = {
435256648Sadrian	4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
436256648Sadrian};
437256648Sadrian
438256648Sadrian/*
439256648Sadrian * Lookup the divisor to use based on the given frequency.
440256648Sadrian *
441256648Sadrian * Returns the divisor to use, or -ve on error.
442256648Sadrian */
443256648Sadrianstatic int
444256648Sadrianarge_mdio_get_divider(struct arge_softc *sc, unsigned long mdio_clock)
445256648Sadrian{
446256648Sadrian	unsigned long ref_clock, t;
447256648Sadrian	const uint32_t *table;
448256648Sadrian	int ndivs;
449256648Sadrian	int i;
450256648Sadrian
451256648Sadrian	/*
452256648Sadrian	 * This is the base MDIO frequency on the SoC.
453256648Sadrian	 * The dividers .. well, divide. Duh.
454256648Sadrian	 */
455256648Sadrian	ref_clock = ar71xx_mdio_freq();
456256648Sadrian
457256648Sadrian	/*
458256648Sadrian	 * If either clock is undefined, just tell the
459256648Sadrian	 * caller to fall through to the defaults.
460256648Sadrian	 */
461256648Sadrian	if (ref_clock == 0 || mdio_clock == 0)
462256648Sadrian		return (-EINVAL);
463256648Sadrian
464256648Sadrian	/*
465256648Sadrian	 * Pick the correct table!
466256648Sadrian	 */
467256648Sadrian	switch (ar71xx_soc) {
468256648Sadrian	case AR71XX_SOC_AR9330:
469256648Sadrian	case AR71XX_SOC_AR9331:
470256648Sadrian	case AR71XX_SOC_AR9341:
471256648Sadrian	case AR71XX_SOC_AR9342:
472256648Sadrian	case AR71XX_SOC_AR9344:
473279510Sadrian	case AR71XX_SOC_QCA9556:
474279510Sadrian	case AR71XX_SOC_QCA9558:
475256648Sadrian		table = ar933x_mdio_div_table;
476256648Sadrian		ndivs = nitems(ar933x_mdio_div_table);
477256648Sadrian		break;
478256648Sadrian
479256648Sadrian	case AR71XX_SOC_AR7240:
480256648Sadrian	case AR71XX_SOC_AR7241:
481256648Sadrian	case AR71XX_SOC_AR7242:
482256648Sadrian		table = ar7240_mdio_div_table;
483256648Sadrian		ndivs = nitems(ar7240_mdio_div_table);
484256648Sadrian		break;
485256648Sadrian
486256648Sadrian	default:
487256648Sadrian		table = ar71xx_mdio_div_table;
488256648Sadrian		ndivs = nitems(ar71xx_mdio_div_table);
489256648Sadrian	}
490256648Sadrian
491256648Sadrian	/*
492256648Sadrian	 * Now, walk through the list and find the first divisor
493256648Sadrian	 * that falls under the target MDIO frequency.
494256648Sadrian	 *
495256648Sadrian	 * The divisors go up, but the corresponding frequencies
496256648Sadrian	 * are actually decreasing.
497256648Sadrian	 */
498256648Sadrian	for (i = 0; i < ndivs; i++) {
499256648Sadrian		t = ref_clock / table[i];
500256648Sadrian		if (t <= mdio_clock) {
501256648Sadrian			return (i);
502256648Sadrian		}
503256648Sadrian	}
504256648Sadrian
505256648Sadrian	ARGEDEBUG(sc, ARGE_DBG_RESET,
506256648Sadrian	    "No divider found; MDIO=%lu Hz; target=%lu Hz\n",
507256648Sadrian		ref_clock, mdio_clock);
508256648Sadrian	return (-ENOENT);
509256648Sadrian}
510256648Sadrian
511256648Sadrian/*
512256575Sadrian * Fetch the MDIO bus clock rate.
513256575Sadrian *
514256575Sadrian * For now, the default is DIV_28 for everything
515256648Sadrian * bar AR934x, which will be DIV_58.
516256575Sadrian *
517256575Sadrian * It will definitely need updating to take into account
518256575Sadrian * the MDIO bus core clock rate and the target clock
519256575Sadrian * rate for the chip.
520256575Sadrian */
521256575Sadrianstatic uint32_t
522256575Sadrianarge_fetch_mdiobus_clock_rate(struct arge_softc *sc)
523256575Sadrian{
524256648Sadrian	int mdio_freq, div;
525256575Sadrian
526256648Sadrian	/*
527256648Sadrian	 * Is the MDIO frequency defined? If so, find a divisor that
528256648Sadrian	 * makes reasonable sense.  Don't overshoot the frequency.
529256648Sadrian	 */
530256648Sadrian	if (resource_int_value(device_get_name(sc->arge_dev),
531256648Sadrian	    device_get_unit(sc->arge_dev),
532256648Sadrian	    "mdio_freq",
533256648Sadrian	    &mdio_freq) == 0) {
534256648Sadrian		sc->arge_mdiofreq = mdio_freq;
535256648Sadrian		div = arge_mdio_get_divider(sc, sc->arge_mdiofreq);
536256648Sadrian		if (bootverbose)
537256648Sadrian			device_printf(sc->arge_dev,
538256648Sadrian			    "%s: mdio ref freq=%llu Hz, target freq=%llu Hz,"
539256648Sadrian			    " divisor index=%d\n",
540256648Sadrian			    __func__,
541256648Sadrian			    (unsigned long long) ar71xx_mdio_freq(),
542256648Sadrian			    (unsigned long long) mdio_freq,
543256648Sadrian			    div);
544256648Sadrian		if (div >= 0)
545256648Sadrian			return (div);
546256648Sadrian	}
547256648Sadrian
548256648Sadrian	/*
549256648Sadrian	 * Default value(s).
550256648Sadrian	 *
551256648Sadrian	 * XXX obviously these need .. fixing.
552256648Sadrian	 *
553256648Sadrian	 * From Linux/OpenWRT:
554256648Sadrian	 *
555256648Sadrian	 * + 7240? DIV_6
556256648Sadrian	 * + Builtin-switch port and not 934x? DIV_10
557256648Sadrian	 * + Not built-in switch port and 934x? DIV_58
558256648Sadrian	 * + .. else DIV_28.
559256648Sadrian	 */
560256575Sadrian	switch (ar71xx_soc) {
561256575Sadrian	case AR71XX_SOC_AR9341:
562256575Sadrian	case AR71XX_SOC_AR9342:
563256575Sadrian	case AR71XX_SOC_AR9344:
564279510Sadrian	case AR71XX_SOC_QCA9556:
565279510Sadrian	case AR71XX_SOC_QCA9558:
566256648Sadrian		return (MAC_MII_CFG_CLOCK_DIV_58);
567256648Sadrian		break;
568256575Sadrian	default:
569256575Sadrian		return (MAC_MII_CFG_CLOCK_DIV_28);
570256575Sadrian	}
571256575Sadrian}
572256575Sadrian
573234862Sadrianstatic void
574234862Sadrianarge_reset_miibus(struct arge_softc *sc)
575234862Sadrian{
576256575Sadrian	uint32_t mdio_div;
577234862Sadrian
578256575Sadrian	mdio_div = arge_fetch_mdiobus_clock_rate(sc);
579256575Sadrian
580256575Sadrian	/*
581256575Sadrian	 * XXX AR934x and later; should we be also resetting the
582256575Sadrian	 * MDIO block(s) using the reset register block?
583256575Sadrian	 */
584256575Sadrian
585256575Sadrian	/* Reset MII bus; program in the default divisor */
586256575Sadrian	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET | mdio_div);
587234862Sadrian	DELAY(100);
588256575Sadrian	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, mdio_div);
589234862Sadrian	DELAY(100);
590234862Sadrian}
591234862Sadrian
592234919Sadrianstatic void
593234919Sadrianarge_fetch_pll_config(struct arge_softc *sc)
594234919Sadrian{
595234919Sadrian	long int val;
596234919Sadrian
597234919Sadrian	if (resource_long_value(device_get_name(sc->arge_dev),
598234919Sadrian	    device_get_unit(sc->arge_dev),
599234919Sadrian	    "pll_10", &val) == 0) {
600234919Sadrian		sc->arge_pllcfg.pll_10 = val;
601234919Sadrian		device_printf(sc->arge_dev, "%s: pll_10 = 0x%x\n",
602234919Sadrian		    __func__, (int) val);
603234919Sadrian	}
604234919Sadrian	if (resource_long_value(device_get_name(sc->arge_dev),
605234919Sadrian	    device_get_unit(sc->arge_dev),
606234919Sadrian	    "pll_100", &val) == 0) {
607234919Sadrian		sc->arge_pllcfg.pll_100 = val;
608234919Sadrian		device_printf(sc->arge_dev, "%s: pll_100 = 0x%x\n",
609234919Sadrian		    __func__, (int) val);
610234919Sadrian	}
611234919Sadrian	if (resource_long_value(device_get_name(sc->arge_dev),
612234919Sadrian	    device_get_unit(sc->arge_dev),
613234919Sadrian	    "pll_1000", &val) == 0) {
614234919Sadrian		sc->arge_pllcfg.pll_1000 = val;
615234919Sadrian		device_printf(sc->arge_dev, "%s: pll_1000 = 0x%x\n",
616234919Sadrian		    __func__, (int) val);
617234919Sadrian	}
618234919Sadrian}
619234919Sadrian
620188808Sgonzostatic int
621188808Sgonzoarge_attach(device_t dev)
622188808Sgonzo{
623188808Sgonzo	struct ifnet		*ifp;
624188808Sgonzo	struct arge_softc	*sc;
625280798Sadrian	int			error = 0, rid, i;
626199234Sgonzo	uint32_t		hint;
627220260Sadrian	long			eeprom_mac_addr = 0;
628234910Sadrian	int			miicfg = 0;
629254690Ssbruno	int			readascii = 0;
630263224Sadrian	int			local_mac = 0;
631280798Sadrian	uint8_t			local_macaddr[ETHER_ADDR_LEN];
632280798Sadrian	char *			local_macstr;
633280798Sadrian	char			devid_str[32];
634280798Sadrian	int			count;
635188808Sgonzo
636188808Sgonzo	sc = device_get_softc(dev);
637188808Sgonzo	sc->arge_dev = dev;
638188808Sgonzo	sc->arge_mac_unit = device_get_unit(dev);
639188808Sgonzo
640220260Sadrian	/*
641280798Sadrian	 * See if there's a "board" MAC address hint available for
642280798Sadrian	 * this particular device.
643280798Sadrian	 *
644280798Sadrian	 * This is in the environment - it'd be nice to use the resource_*()
645280798Sadrian	 * routines, but at the moment the system is booting, the resource hints
646280798Sadrian	 * are set to the 'static' map so they're not pulling from kenv.
647280798Sadrian	 */
648280798Sadrian	snprintf(devid_str, 32, "hint.%s.%d.macaddr",
649280798Sadrian	    device_get_name(dev),
650280798Sadrian	    device_get_unit(dev));
651280798Sadrian	if ((local_macstr = kern_getenv(devid_str)) != NULL) {
652280798Sadrian		uint32_t tmpmac[ETHER_ADDR_LEN];
653280798Sadrian
654280798Sadrian		/* Have a MAC address; should use it */
655280798Sadrian		device_printf(dev, "Overriding MAC address from environment: '%s'\n",
656280798Sadrian		    local_macstr);
657280798Sadrian
658280798Sadrian		/* Extract out the MAC address */
659280798Sadrian		/* XXX this should all be a generic method */
660280798Sadrian		count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
661280798Sadrian		    &tmpmac[0], &tmpmac[1],
662280798Sadrian		    &tmpmac[2], &tmpmac[3],
663280798Sadrian		    &tmpmac[4], &tmpmac[5]);
664280798Sadrian		if (count == 6) {
665280798Sadrian			/* Valid! */
666280798Sadrian			local_mac = 1;
667280798Sadrian			for (i = 0; i < ETHER_ADDR_LEN; i++)
668280798Sadrian				local_macaddr[i] = tmpmac[i];
669280798Sadrian		}
670280798Sadrian		/* Done! */
671280798Sadrian		freeenv(local_macstr);
672280798Sadrian		local_macstr = NULL;
673280798Sadrian	}
674280798Sadrian
675280798Sadrian	/*
676289476Sadrian	 * Hardware workarounds.
677289476Sadrian	 */
678289476Sadrian	switch (ar71xx_soc) {
679289744Sadrian	case AR71XX_SOC_AR9330:
680289744Sadrian	case AR71XX_SOC_AR9331:
681289898Sadrian	case AR71XX_SOC_AR9341:
682289898Sadrian	case AR71XX_SOC_AR9342:
683289898Sadrian	case AR71XX_SOC_AR9344:
684289476Sadrian	case AR71XX_SOC_QCA9556:
685289476Sadrian	case AR71XX_SOC_QCA9558:
686289476Sadrian		/* Arbitrary alignment */
687289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE;
688289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE;
689289476Sadrian		break;
690289476Sadrian	default:
691289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE;
692289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE;
693289476Sadrian		break;
694289476Sadrian	}
695289476Sadrian
696289476Sadrian	/*
697220260Sadrian	 * Some units (eg the TP-Link WR-1043ND) do not have a convenient
698220260Sadrian	 * EEPROM location to read the ethernet MAC address from.
699220260Sadrian	 * OpenWRT simply snaffles it from a fixed location.
700220260Sadrian	 *
701220260Sadrian	 * Since multiple units seem to use this feature, include
702220260Sadrian	 * a method of setting the MAC address based on an flash location
703220260Sadrian	 * in CPU address space.
704254690Ssbruno	 *
705254690Ssbruno	 * Some vendors have decided to store the mac address as a literal
706254690Ssbruno	 * string of 18 characters in xx:xx:xx:xx:xx:xx format instead of
707254690Ssbruno	 * an array of numbers.  Expose a hint to turn on this conversion
708254690Ssbruno	 * feature via strtol()
709220260Sadrian	 */
710280798Sadrian	 if (local_mac == 0 && resource_long_value(device_get_name(dev),
711280798Sadrian	     device_get_unit(dev), "eeprommac", &eeprom_mac_addr) == 0) {
712263224Sadrian		local_mac = 1;
713220260Sadrian		int i;
714232628Sray		const char *mac =
715232628Sray		    (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr);
716220260Sadrian		device_printf(dev, "Overriding MAC from EEPROM\n");
717254690Ssbruno		if (resource_int_value(device_get_name(dev), device_get_unit(dev),
718254690Ssbruno			"readascii", &readascii) == 0) {
719254690Ssbruno			device_printf(dev, "Vendor stores MAC in ASCII format\n");
720254690Ssbruno			for (i = 0; i < 6; i++) {
721280798Sadrian				local_macaddr[i] = strtol(&(mac[i*3]), NULL, 16);
722254690Ssbruno			}
723254690Ssbruno		} else {
724254690Ssbruno			for (i = 0; i < 6; i++) {
725280798Sadrian				local_macaddr[i] = mac[i];
726254690Ssbruno			}
727220260Sadrian		}
728220260Sadrian	}
729220260Sadrian
730232627Sray	KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)),
731188808Sgonzo	    ("if_arge: Only MAC0 and MAC1 supported"));
732188808Sgonzo
733188808Sgonzo	/*
734234919Sadrian	 * Fetch the PLL configuration.
735234919Sadrian	 */
736234919Sadrian	arge_fetch_pll_config(sc);
737234919Sadrian
738234919Sadrian	/*
739234910Sadrian	 * Get the MII configuration, if applicable.
740234910Sadrian	 */
741234910Sadrian	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
742234910Sadrian	    "miimode", &miicfg) == 0) {
743234910Sadrian		/* XXX bounds check? */
744234910Sadrian		device_printf(dev, "%s: overriding MII mode to '%s'\n",
745234910Sadrian		    __func__, arge_miicfg_str[miicfg]);
746234910Sadrian		sc->arge_miicfg = miicfg;
747234910Sadrian	}
748234910Sadrian
749234910Sadrian	/*
750188808Sgonzo	 *  Get which PHY of 5 available we should use for this unit
751188808Sgonzo	 */
752234862Sadrian	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
753234862Sadrian	    "phymask", &sc->arge_phymask) != 0) {
754188808Sgonzo		/*
755232627Sray		 * Use port 4 (WAN) for GE0. For any other port use
756232627Sray		 * its PHY the same as its unit number
757188808Sgonzo		 */
758188808Sgonzo		if (sc->arge_mac_unit == 0)
759234862Sadrian			sc->arge_phymask = (1 << 4);
760188808Sgonzo		else
761199234Sgonzo			/* Use all phys up to 4 */
762234862Sadrian			sc->arge_phymask = (1 << 4) - 1;
763188808Sgonzo
764234862Sadrian		device_printf(dev, "No PHY specified, using mask %d\n", sc->arge_phymask);
765188808Sgonzo	}
766188808Sgonzo
767199234Sgonzo	/*
768279791Sadrian	 * Get default/hard-coded media & duplex mode.
769199234Sgonzo	 */
770232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
771199234Sgonzo	    "media", &hint) != 0)
772199234Sgonzo		hint = 0;
773188808Sgonzo
774199234Sgonzo	if (hint == 1000)
775199234Sgonzo		sc->arge_media_type = IFM_1000_T;
776279791Sadrian	else if (hint == 100)
777279791Sadrian		sc->arge_media_type = IFM_100_TX;
778279791Sadrian	else if (hint == 10)
779279791Sadrian		sc->arge_media_type = IFM_10_T;
780199234Sgonzo	else
781279791Sadrian		sc->arge_media_type = 0;
782199234Sgonzo
783232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
784199234Sgonzo	    "fduplex", &hint) != 0)
785199234Sgonzo		hint = 1;
786199234Sgonzo
787199234Sgonzo	if (hint)
788199234Sgonzo		sc->arge_duplex_mode = IFM_FDX;
789199234Sgonzo	else
790199234Sgonzo		sc->arge_duplex_mode = 0;
791199234Sgonzo
792188808Sgonzo	mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
793188808Sgonzo	    MTX_DEF);
794188808Sgonzo	callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0);
795188808Sgonzo	TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc);
796188808Sgonzo
797188808Sgonzo	/* Map control/status registers. */
798188808Sgonzo	sc->arge_rid = 0;
799234862Sadrian	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
800234862Sadrian	    &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE);
801188808Sgonzo
802188808Sgonzo	if (sc->arge_res == NULL) {
803188808Sgonzo		device_printf(dev, "couldn't map memory\n");
804188808Sgonzo		error = ENXIO;
805188808Sgonzo		goto fail;
806188808Sgonzo	}
807188808Sgonzo
808188808Sgonzo	/* Allocate interrupts */
809188808Sgonzo	rid = 0;
810232627Sray	sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
811188808Sgonzo	    RF_SHAREABLE | RF_ACTIVE);
812188808Sgonzo
813188808Sgonzo	if (sc->arge_irq == NULL) {
814188808Sgonzo		device_printf(dev, "couldn't map interrupt\n");
815188808Sgonzo		error = ENXIO;
816188808Sgonzo		goto fail;
817188808Sgonzo	}
818188808Sgonzo
819188808Sgonzo	/* Allocate ifnet structure. */
820188808Sgonzo	ifp = sc->arge_ifp = if_alloc(IFT_ETHER);
821188808Sgonzo
822188808Sgonzo	if (ifp == NULL) {
823188808Sgonzo		device_printf(dev, "couldn't allocate ifnet structure\n");
824188808Sgonzo		error = ENOSPC;
825188808Sgonzo		goto fail;
826188808Sgonzo	}
827188808Sgonzo
828188808Sgonzo	ifp->if_softc = sc;
829188808Sgonzo	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
830188808Sgonzo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
831188808Sgonzo	ifp->if_ioctl = arge_ioctl;
832188808Sgonzo	ifp->if_start = arge_start;
833188808Sgonzo	ifp->if_init = arge_init;
834198932Sgonzo	sc->arge_if_flags = ifp->if_flags;
835188808Sgonzo
836188808Sgonzo	/* XXX: add real size */
837207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
838207554Ssobomax	ifp->if_snd.ifq_maxlen = ifqmaxlen;
839188808Sgonzo	IFQ_SET_READY(&ifp->if_snd);
840188808Sgonzo
841268235Sloos	/* Tell the upper layer(s) we support long frames. */
842268235Sloos	ifp->if_capabilities |= IFCAP_VLAN_MTU;
843268235Sloos
844188808Sgonzo	ifp->if_capenable = ifp->if_capabilities;
845192783Sgonzo#ifdef DEVICE_POLLING
846192783Sgonzo	ifp->if_capabilities |= IFCAP_POLLING;
847192783Sgonzo#endif
848188808Sgonzo
849280798Sadrian	/* If there's a local mac defined, copy that in */
850280798Sadrian	if (local_mac == 1) {
851280798Sadrian		(void) ar71xx_mac_addr_init(sc->arge_eaddr,
852280798Sadrian		    local_macaddr, 0, 0);
853280798Sadrian	} else {
854192179Sgonzo		/*
855192179Sgonzo		 * No MAC address configured. Generate the random one.
856192179Sgonzo		 */
857198933Sgonzo		if  (bootverbose)
858232627Sray			device_printf(dev,
859192179Sgonzo			    "Generating random ethernet address.\n");
860280124Sadrian		(void) ar71xx_mac_addr_random_init(sc->arge_eaddr);
861192179Sgonzo	}
862263224Sadrian
863188808Sgonzo	if (arge_dma_alloc(sc) != 0) {
864188808Sgonzo		error = ENXIO;
865188808Sgonzo		goto fail;
866188808Sgonzo	}
867188808Sgonzo
868234862Sadrian	/*
869234862Sadrian	 * Don't do this for the MDIO bus case - it's already done
870234862Sadrian	 * as part of the MDIO bus attachment.
871234862Sadrian	 */
872234862Sadrian#if !defined(ARGE_MDIO)
873192569Sdwhite	/* Initialize the MAC block */
874234862Sadrian	arge_reset_mac(sc);
875234862Sadrian	arge_reset_miibus(sc);
876234862Sadrian#endif
877232627Sray
878234910Sadrian	/* Configure MII mode, just for convienence */
879234910Sadrian	if (sc->arge_miicfg != 0)
880234910Sadrian		ar71xx_device_set_mii_if(sc->arge_mac_unit, sc->arge_miicfg);
881234910Sadrian
882232627Sray	/*
883188808Sgonzo	 * Set all Ethernet address registers to the same initial values
884232627Sray	 * set all four addresses to 66-88-aa-cc-dd-ee
885188808Sgonzo	 */
886234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, (sc->arge_eaddr[2] << 24)
887234862Sadrian	    | (sc->arge_eaddr[3] << 16) | (sc->arge_eaddr[4] << 8)
888234862Sadrian	    | sc->arge_eaddr[5]);
889234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (sc->arge_eaddr[0] << 8)
890234862Sadrian	    | sc->arge_eaddr[1]);
891188808Sgonzo
892232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0,
893188808Sgonzo	    FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT);
894188808Sgonzo
895289476Sadrian	/*
896289476Sadrian	 * SoC specific bits.
897289476Sadrian	 */
898219589Sadrian	switch (ar71xx_soc) {
899219589Sadrian		case AR71XX_SOC_AR7240:
900219589Sadrian		case AR71XX_SOC_AR7241:
901219589Sadrian		case AR71XX_SOC_AR7242:
902249123Sadrian		case AR71XX_SOC_AR9330:
903249123Sadrian		case AR71XX_SOC_AR9331:
904256575Sadrian		case AR71XX_SOC_AR9341:
905256575Sadrian		case AR71XX_SOC_AR9342:
906256575Sadrian		case AR71XX_SOC_AR9344:
907279510Sadrian		case AR71XX_SOC_QCA9556:
908279510Sadrian		case AR71XX_SOC_QCA9558:
909219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0010ffff);
910219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x015500aa);
911219589Sadrian			break;
912256575Sadrian		/* AR71xx, AR913x */
913219589Sadrian		default:
914219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000);
915219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff);
916219589Sadrian	}
917219589Sadrian
918232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH,
919192783Sgonzo	    FIFO_RX_FILTMATCH_DEFAULT);
920188808Sgonzo
921232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
922192783Sgonzo	    FIFO_RX_FILTMASK_DEFAULT);
923188808Sgonzo
924234862Sadrian#if defined(ARGE_MDIO)
925234862Sadrian	sc->arge_miiproxy = mii_attach_proxy(sc->arge_dev);
926234862Sadrian#endif
927199234Sgonzo
928234862Sadrian	device_printf(sc->arge_dev, "finishing attachment, phymask %04x"
929234862Sadrian	    ", proxy %s \n", sc->arge_phymask, sc->arge_miiproxy == NULL ?
930234862Sadrian	    "null" : "set");
931234862Sadrian	for (i = 0; i < ARGE_NPHY; i++) {
932234862Sadrian		if (((1 << i) & sc->arge_phymask) != 0) {
933234862Sadrian			error = mii_attach(sc->arge_miiproxy != NULL ?
934234862Sadrian			    sc->arge_miiproxy : sc->arge_dev,
935234862Sadrian			    &sc->arge_miibus, sc->arge_ifp,
936234862Sadrian			    arge_ifmedia_upd, arge_ifmedia_sts,
937234862Sadrian			    BMSR_DEFCAPMASK, i, MII_OFFSET_ANY, 0);
938234862Sadrian			if (error != 0) {
939234862Sadrian				device_printf(sc->arge_dev, "unable to attach"
940234862Sadrian				    " PHY %d: %d\n", i, error);
941234862Sadrian				goto fail;
942234862Sadrian			}
943199234Sgonzo		}
944199234Sgonzo	}
945279791Sadrian
946234862Sadrian	if (sc->arge_miibus == NULL) {
947234862Sadrian		/* no PHY, so use hard-coded values */
948279791Sadrian		ifmedia_init(&sc->arge_ifmedia, 0,
949199234Sgonzo		    arge_multiphy_mediachange,
950199234Sgonzo		    arge_multiphy_mediastatus);
951199234Sgonzo		ifmedia_add(&sc->arge_ifmedia,
952232627Sray		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode,
953199234Sgonzo		    0, NULL);
954199234Sgonzo		ifmedia_set(&sc->arge_ifmedia,
955199234Sgonzo		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode);
956199234Sgonzo		arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode);
957199234Sgonzo	}
958199234Sgonzo
959188808Sgonzo	/* Call MI attach routine. */
960234862Sadrian	ether_ifattach(sc->arge_ifp, sc->arge_eaddr);
961188808Sgonzo
962188808Sgonzo	/* Hook interrupt last to avoid having to lock softc */
963234862Sadrian	error = bus_setup_intr(sc->arge_dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
964188808Sgonzo	    arge_intr_filter, arge_intr, sc, &sc->arge_intrhand);
965188808Sgonzo
966188808Sgonzo	if (error) {
967234862Sadrian		device_printf(sc->arge_dev, "couldn't set up irq\n");
968234862Sadrian		ether_ifdetach(sc->arge_ifp);
969188808Sgonzo		goto fail;
970188808Sgonzo	}
971188808Sgonzo
972209802Sadrian	/* setup sysctl variables */
973234862Sadrian	arge_attach_sysctl(sc->arge_dev);
974209802Sadrian
975188808Sgonzofail:
976234862Sadrian	if (error)
977188808Sgonzo		arge_detach(dev);
978188808Sgonzo
979188808Sgonzo	return (error);
980188808Sgonzo}
981188808Sgonzo
982188808Sgonzostatic int
983188808Sgonzoarge_detach(device_t dev)
984188808Sgonzo{
985192783Sgonzo	struct arge_softc	*sc = device_get_softc(dev);
986188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
987188808Sgonzo
988232628Sray	KASSERT(mtx_initialized(&sc->arge_mtx),
989232628Sray	    ("arge mutex not initialized"));
990188808Sgonzo
991188808Sgonzo	/* These should only be active if attach succeeded */
992188808Sgonzo	if (device_is_attached(dev)) {
993188808Sgonzo		ARGE_LOCK(sc);
994188808Sgonzo		sc->arge_detach = 1;
995192783Sgonzo#ifdef DEVICE_POLLING
996192783Sgonzo		if (ifp->if_capenable & IFCAP_POLLING)
997192783Sgonzo			ether_poll_deregister(ifp);
998192783Sgonzo#endif
999192783Sgonzo
1000188808Sgonzo		arge_stop(sc);
1001188808Sgonzo		ARGE_UNLOCK(sc);
1002188808Sgonzo		taskqueue_drain(taskqueue_swi, &sc->arge_link_task);
1003188808Sgonzo		ether_ifdetach(ifp);
1004188808Sgonzo	}
1005188808Sgonzo
1006188808Sgonzo	if (sc->arge_miibus)
1007188808Sgonzo		device_delete_child(dev, sc->arge_miibus);
1008199234Sgonzo
1009234862Sadrian	if (sc->arge_miiproxy)
1010234862Sadrian		device_delete_child(dev, sc->arge_miiproxy);
1011234862Sadrian
1012188808Sgonzo	bus_generic_detach(dev);
1013188808Sgonzo
1014188808Sgonzo	if (sc->arge_intrhand)
1015188808Sgonzo		bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand);
1016188808Sgonzo
1017188808Sgonzo	if (sc->arge_res)
1018232627Sray		bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid,
1019188808Sgonzo		    sc->arge_res);
1020188808Sgonzo
1021188808Sgonzo	if (ifp)
1022188808Sgonzo		if_free(ifp);
1023188808Sgonzo
1024188808Sgonzo	arge_dma_free(sc);
1025188808Sgonzo
1026188808Sgonzo	mtx_destroy(&sc->arge_mtx);
1027188808Sgonzo
1028188808Sgonzo	return (0);
1029188808Sgonzo
1030188808Sgonzo}
1031188808Sgonzo
1032188808Sgonzostatic int
1033188808Sgonzoarge_suspend(device_t dev)
1034188808Sgonzo{
1035188808Sgonzo
1036188808Sgonzo	panic("%s", __func__);
1037188808Sgonzo	return 0;
1038188808Sgonzo}
1039188808Sgonzo
1040188808Sgonzostatic int
1041188808Sgonzoarge_resume(device_t dev)
1042188808Sgonzo{
1043188808Sgonzo
1044188808Sgonzo	panic("%s", __func__);
1045188808Sgonzo	return 0;
1046188808Sgonzo}
1047188808Sgonzo
1048194059Sgonzostatic int
1049188808Sgonzoarge_shutdown(device_t dev)
1050188808Sgonzo{
1051188808Sgonzo	struct arge_softc	*sc;
1052188808Sgonzo
1053188808Sgonzo	sc = device_get_softc(dev);
1054188808Sgonzo
1055188808Sgonzo	ARGE_LOCK(sc);
1056188808Sgonzo	arge_stop(sc);
1057188808Sgonzo	ARGE_UNLOCK(sc);
1058194059Sgonzo
1059194059Sgonzo	return (0);
1060188808Sgonzo}
1061188808Sgonzo
1062234862Sadrianstatic void
1063234862Sadrianarge_hinted_child(device_t bus, const char *dname, int dunit)
1064234862Sadrian{
1065234862Sadrian	BUS_ADD_CHILD(bus, 0, dname, dunit);
1066234862Sadrian	device_printf(bus, "hinted child %s%d\n", dname, dunit);
1067234862Sadrian}
1068234862Sadrian
1069188808Sgonzostatic int
1070188808Sgonzoarge_miibus_readreg(device_t dev, int phy, int reg)
1071188808Sgonzo{
1072188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
1073188808Sgonzo	int i, result;
1074232627Sray	uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT)
1075188808Sgonzo	    | (reg & MAC_MII_REG_MASK);
1076188808Sgonzo
1077199038Sgonzo	mtx_lock(&miibus_mtx);
1078234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
1079234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
1080234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
1081188808Sgonzo
1082188808Sgonzo	i = ARGE_MII_TIMEOUT;
1083234862Sadrian	while ((ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR) &
1084290212Sadrian	    MAC_MII_INDICATOR_BUSY) && (i--)) {
1085290212Sadrian		ARGE_MDIO_BARRIER_READ(sc);
1086188808Sgonzo		DELAY(5);
1087290212Sadrian	}
1088188808Sgonzo
1089188808Sgonzo	if (i < 0) {
1090199038Sgonzo		mtx_unlock(&miibus_mtx);
1091220354Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__);
1092188808Sgonzo		/* XXX: return ERRNO istead? */
1093188808Sgonzo		return (-1);
1094188808Sgonzo	}
1095188808Sgonzo
1096234862Sadrian	result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
1097290212Sadrian	ARGE_MDIO_BARRIER_READ(sc);
1098234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
1099199038Sgonzo	mtx_unlock(&miibus_mtx);
1100199038Sgonzo
1101232628Sray	ARGEDEBUG(sc, ARGE_DBG_MII,
1102232628Sray	    "%s: phy=%d, reg=%02x, value[%08x]=%04x\n",
1103232628Sray	    __func__, phy, reg, addr, result);
1104188808Sgonzo
1105188808Sgonzo	return (result);
1106188808Sgonzo}
1107188808Sgonzo
1108188808Sgonzostatic int
1109188808Sgonzoarge_miibus_writereg(device_t dev, int phy, int reg, int data)
1110188808Sgonzo{
1111188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
1112188808Sgonzo	int i;
1113232627Sray	uint32_t addr =
1114196794Sgonzo	    (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK);
1115188808Sgonzo
1116234862Sadrian	ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n", __func__,
1117234862Sadrian	    phy, reg, data);
1118199038Sgonzo
1119199038Sgonzo	mtx_lock(&miibus_mtx);
1120234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
1121234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CONTROL, data);
1122188808Sgonzo
1123188808Sgonzo	i = ARGE_MII_TIMEOUT;
1124234862Sadrian	while ((ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR) &
1125290212Sadrian	    MAC_MII_INDICATOR_BUSY) && (i--)) {
1126290212Sadrian		ARGE_MDIO_BARRIER_READ(sc);
1127188808Sgonzo		DELAY(5);
1128290212Sadrian	}
1129188808Sgonzo
1130199038Sgonzo	mtx_unlock(&miibus_mtx);
1131199038Sgonzo
1132188808Sgonzo	if (i < 0) {
1133220354Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__);
1134188808Sgonzo		/* XXX: return ERRNO istead? */
1135188808Sgonzo		return (-1);
1136188808Sgonzo	}
1137188808Sgonzo
1138188808Sgonzo	return (0);
1139188808Sgonzo}
1140188808Sgonzo
1141188808Sgonzostatic void
1142188808Sgonzoarge_miibus_statchg(device_t dev)
1143188808Sgonzo{
1144232627Sray	struct arge_softc	*sc;
1145188808Sgonzo
1146188808Sgonzo	sc = device_get_softc(dev);
1147188808Sgonzo	taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task);
1148188808Sgonzo}
1149188808Sgonzo
1150188808Sgonzostatic void
1151188808Sgonzoarge_link_task(void *arg, int pending)
1152188808Sgonzo{
1153188808Sgonzo	struct arge_softc	*sc;
1154232914Sadrian	sc = (struct arge_softc *)arg;
1155232914Sadrian
1156232914Sadrian	ARGE_LOCK(sc);
1157232914Sadrian	arge_update_link_locked(sc);
1158232914Sadrian	ARGE_UNLOCK(sc);
1159232914Sadrian}
1160232914Sadrian
1161232914Sadrianstatic void
1162232914Sadrianarge_update_link_locked(struct arge_softc *sc)
1163232914Sadrian{
1164188808Sgonzo	struct mii_data		*mii;
1165188808Sgonzo	struct ifnet		*ifp;
1166199234Sgonzo	uint32_t		media, duplex;
1167188808Sgonzo
1168188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1169188808Sgonzo	ifp = sc->arge_ifp;
1170188808Sgonzo	if (mii == NULL || ifp == NULL ||
1171188808Sgonzo	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1172188808Sgonzo		return;
1173188808Sgonzo	}
1174188808Sgonzo
1175279791Sadrian	/*
1176279791Sadrian	 * If we have a static media type configured, then
1177279791Sadrian	 * use that.  Some PHY configurations (eg QCA955x -> AR8327)
1178279791Sadrian	 * use a static speed/duplex between the SoC and switch,
1179279791Sadrian	 * even though the front-facing PHY speed changes.
1180279791Sadrian	 */
1181279791Sadrian	if (sc->arge_media_type != 0) {
1182279791Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s: fixed; media=%d, duplex=%d\n",
1183279791Sadrian		    __func__,
1184279791Sadrian		    sc->arge_media_type,
1185279791Sadrian		    sc->arge_duplex_mode);
1186279791Sadrian		if (mii->mii_media_status & IFM_ACTIVE) {
1187279791Sadrian			sc->arge_link_status = 1;
1188279791Sadrian		} else {
1189279791Sadrian			sc->arge_link_status = 0;
1190279791Sadrian		}
1191279791Sadrian		arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode);
1192279791Sadrian	}
1193279791Sadrian
1194188808Sgonzo	if (mii->mii_media_status & IFM_ACTIVE) {
1195188808Sgonzo
1196188808Sgonzo		media = IFM_SUBTYPE(mii->mii_media_active);
1197188808Sgonzo		if (media != IFM_NONE) {
1198188808Sgonzo			sc->arge_link_status = 1;
1199199234Sgonzo			duplex = mii->mii_media_active & IFM_GMASK;
1200234907Sadrian			ARGEDEBUG(sc, ARGE_DBG_MII, "%s: media=%d, duplex=%d\n",
1201234907Sadrian			    __func__,
1202234907Sadrian			    media,
1203234907Sadrian			    duplex);
1204199234Sgonzo			arge_set_pll(sc, media, duplex);
1205199234Sgonzo		}
1206232914Sadrian	} else {
1207199234Sgonzo		sc->arge_link_status = 0;
1208232914Sadrian	}
1209199234Sgonzo}
1210192783Sgonzo
1211199234Sgonzostatic void
1212199234Sgonzoarge_set_pll(struct arge_softc *sc, int media, int duplex)
1213199234Sgonzo{
1214211511Sadrian	uint32_t		cfg, ifcontrol, rx_filtmask;
1215234907Sadrian	uint32_t		fifo_tx, pll;
1216211511Sadrian	int if_speed;
1217192783Sgonzo
1218279791Sadrian	/*
1219279791Sadrian	 * XXX Verify - is this valid for all chips?
1220279791Sadrian	 * QCA955x (and likely some of the earlier chips!) define
1221279791Sadrian	 * this as nibble mode and byte mode, and those have to do
1222279791Sadrian	 * with the interface type (MII/SMII versus GMII/RGMII.)
1223279791Sadrian	 */
1224234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "set_pll(%04x, %s)\n", media,
1225234862Sadrian	    duplex == IFM_FDX ? "full" : "half");
1226199234Sgonzo	cfg = ARGE_READ(sc, AR71XX_MAC_CFG2);
1227232627Sray	cfg &= ~(MAC_CFG2_IFACE_MODE_1000
1228232627Sray	    | MAC_CFG2_IFACE_MODE_10_100
1229199234Sgonzo	    | MAC_CFG2_FULL_DUPLEX);
1230188808Sgonzo
1231199234Sgonzo	if (duplex == IFM_FDX)
1232199234Sgonzo		cfg |= MAC_CFG2_FULL_DUPLEX;
1233188808Sgonzo
1234199234Sgonzo	ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL);
1235199234Sgonzo	ifcontrol &= ~MAC_IFCONTROL_SPEED;
1236232627Sray	rx_filtmask =
1237199234Sgonzo	    ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK);
1238199234Sgonzo	rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE;
1239188808Sgonzo
1240199234Sgonzo	switch(media) {
1241199234Sgonzo	case IFM_10_T:
1242199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
1243211511Sadrian		if_speed = 10;
1244199234Sgonzo		break;
1245199234Sgonzo	case IFM_100_TX:
1246199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
1247199234Sgonzo		ifcontrol |= MAC_IFCONTROL_SPEED;
1248211511Sadrian		if_speed = 100;
1249199234Sgonzo		break;
1250199234Sgonzo	case IFM_1000_T:
1251199234Sgonzo	case IFM_1000_SX:
1252199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_1000;
1253199234Sgonzo		rx_filtmask |= FIFO_RX_MASK_BYTE_MODE;
1254211511Sadrian		if_speed = 1000;
1255199234Sgonzo		break;
1256199234Sgonzo	default:
1257211511Sadrian		if_speed = 100;
1258232627Sray		device_printf(sc->arge_dev,
1259199234Sgonzo		    "Unknown media %d\n", media);
1260199234Sgonzo	}
1261188808Sgonzo
1262234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: if_speed=%d\n", __func__, if_speed);
1263234907Sadrian
1264219589Sadrian	switch (ar71xx_soc) {
1265219589Sadrian		case AR71XX_SOC_AR7240:
1266219589Sadrian		case AR71XX_SOC_AR7241:
1267219589Sadrian		case AR71XX_SOC_AR7242:
1268249123Sadrian		case AR71XX_SOC_AR9330:
1269249123Sadrian		case AR71XX_SOC_AR9331:
1270256575Sadrian		case AR71XX_SOC_AR9341:
1271256575Sadrian		case AR71XX_SOC_AR9342:
1272256575Sadrian		case AR71XX_SOC_AR9344:
1273279510Sadrian		case AR71XX_SOC_QCA9556:
1274279510Sadrian		case AR71XX_SOC_QCA9558:
1275219589Sadrian			fifo_tx = 0x01f00140;
1276219589Sadrian			break;
1277219589Sadrian		case AR71XX_SOC_AR9130:
1278219589Sadrian		case AR71XX_SOC_AR9132:
1279219589Sadrian			fifo_tx = 0x00780fff;
1280219589Sadrian			break;
1281256575Sadrian		/* AR71xx */
1282219589Sadrian		default:
1283219589Sadrian			fifo_tx = 0x008001ff;
1284219589Sadrian	}
1285188808Sgonzo
1286199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg);
1287199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol);
1288232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
1289199234Sgonzo	    rx_filtmask);
1290219589Sadrian	ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, fifo_tx);
1291188808Sgonzo
1292234919Sadrian	/* fetch PLL registers */
1293234907Sadrian	pll = ar71xx_device_get_eth_pll(sc->arge_mac_unit, if_speed);
1294234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: pll=0x%x\n", __func__, pll);
1295234907Sadrian
1296234919Sadrian	/* Override if required by platform data */
1297234919Sadrian	if (if_speed == 10 && sc->arge_pllcfg.pll_10 != 0)
1298234919Sadrian		pll = sc->arge_pllcfg.pll_10;
1299234919Sadrian	else if (if_speed == 100 && sc->arge_pllcfg.pll_100 != 0)
1300234919Sadrian		pll = sc->arge_pllcfg.pll_100;
1301234919Sadrian	else if (if_speed == 1000 && sc->arge_pllcfg.pll_1000 != 0)
1302234919Sadrian		pll = sc->arge_pllcfg.pll_1000;
1303234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: final pll=0x%x\n", __func__, pll);
1304234919Sadrian
1305234907Sadrian	/* XXX ensure pll != 0 */
1306234907Sadrian	ar71xx_device_set_pll_ge(sc->arge_mac_unit, if_speed, pll);
1307234907Sadrian
1308234907Sadrian	/* set MII registers */
1309234992Sadrian	/*
1310234992Sadrian	 * This was introduced to match what the Linux ag71xx ethernet
1311234992Sadrian	 * driver does.  For the AR71xx case, it does set the port
1312234992Sadrian	 * MII speed.  However, if this is done, non-gigabit speeds
1313234992Sadrian	 * are not at all reliable when speaking via RGMII through
1314234992Sadrian	 * 'bridge' PHY port that's pretending to be a local PHY.
1315234992Sadrian	 *
1316234992Sadrian	 * Until that gets root caused, and until an AR71xx + normal
1317234992Sadrian	 * PHY board is tested, leave this disabled.
1318234992Sadrian	 */
1319234992Sadrian#if 0
1320234907Sadrian	ar71xx_device_set_mii_speed(sc->arge_mac_unit, if_speed);
1321234992Sadrian#endif
1322188808Sgonzo}
1323188808Sgonzo
1324199234Sgonzo
1325188808Sgonzostatic void
1326188808Sgonzoarge_reset_dma(struct arge_softc *sc)
1327188808Sgonzo{
1328279791Sadrian
1329279791Sadrian	ARGEDEBUG(sc, ARGE_DBG_RESET, "%s: called\n", __func__);
1330279791Sadrian
1331188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0);
1332188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0);
1333188808Sgonzo
1334188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0);
1335188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0);
1336188808Sgonzo
1337188808Sgonzo	/* Clear all possible RX interrupts */
1338192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD)
1339188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
1340188808Sgonzo
1341232627Sray	/*
1342188808Sgonzo	 * Clear all possible TX interrupts
1343188808Sgonzo	 */
1344192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT)
1345188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
1346188808Sgonzo
1347232627Sray	/*
1348188808Sgonzo	 * Now Rx/Tx errors
1349188808Sgonzo	 */
1350232627Sray	ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS,
1351188808Sgonzo	    DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW);
1352232627Sray	ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS,
1353188808Sgonzo	    DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN);
1354232912Sadrian
1355232912Sadrian	/*
1356232912Sadrian	 * Force a DDR flush so any pending data is properly
1357232912Sadrian	 * flushed to RAM before underlying buffers are freed.
1358232912Sadrian	 */
1359232912Sadrian	arge_flush_ddr(sc);
1360188808Sgonzo}
1361188808Sgonzo
1362188808Sgonzostatic void
1363188808Sgonzoarge_init(void *xsc)
1364188808Sgonzo{
1365188808Sgonzo	struct arge_softc	 *sc = xsc;
1366188808Sgonzo
1367188808Sgonzo	ARGE_LOCK(sc);
1368188808Sgonzo	arge_init_locked(sc);
1369188808Sgonzo	ARGE_UNLOCK(sc);
1370188808Sgonzo}
1371188808Sgonzo
1372188808Sgonzostatic void
1373188808Sgonzoarge_init_locked(struct arge_softc *sc)
1374188808Sgonzo{
1375188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
1376188808Sgonzo	struct mii_data		*mii;
1377188808Sgonzo
1378188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1379188808Sgonzo
1380255021Sloos	if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1381255021Sloos		return;
1382188808Sgonzo
1383188808Sgonzo	/* Init circular RX list. */
1384188808Sgonzo	if (arge_rx_ring_init(sc) != 0) {
1385188808Sgonzo		device_printf(sc->arge_dev,
1386188808Sgonzo		    "initialization failed: no memory for rx buffers\n");
1387188808Sgonzo		arge_stop(sc);
1388188808Sgonzo		return;
1389188808Sgonzo	}
1390188808Sgonzo
1391188808Sgonzo	/* Init tx descriptors. */
1392188808Sgonzo	arge_tx_ring_init(sc);
1393188808Sgonzo
1394188808Sgonzo	arge_reset_dma(sc);
1395188808Sgonzo
1396199234Sgonzo	if (sc->arge_miibus) {
1397199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
1398199234Sgonzo		mii_mediachg(mii);
1399199234Sgonzo	}
1400199234Sgonzo	else {
1401199234Sgonzo		/*
1402199234Sgonzo		 * Sun always shines over multiPHY interface
1403199234Sgonzo		 */
1404199234Sgonzo		sc->arge_link_status = 1;
1405199234Sgonzo	}
1406199234Sgonzo
1407188808Sgonzo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1408188808Sgonzo	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1409188808Sgonzo
1410232914Sadrian	if (sc->arge_miibus) {
1411199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
1412232914Sadrian		arge_update_link_locked(sc);
1413232914Sadrian	}
1414192783Sgonzo
1415188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0));
1416188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0));
1417188808Sgonzo
1418188808Sgonzo	/* Start listening */
1419188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
1420188808Sgonzo
1421188808Sgonzo	/* Enable interrupts */
1422188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1423188808Sgonzo}
1424188808Sgonzo
1425188808Sgonzo/*
1426209807Sadrian * Return whether the mbuf chain is correctly aligned
1427209807Sadrian * for the arge TX engine.
1428209807Sadrian *
1429289476Sadrian * All the MACs have a length requirement: any non-final
1430289476Sadrian * fragment (ie, descriptor with MORE bit set) needs to have
1431289476Sadrian * a length divisible by 4.
1432256649Sadrian *
1433289476Sadrian * The AR71xx, AR913x require the start address also be
1434289476Sadrian * DWORD aligned.  The later MACs don't.
1435209807Sadrian */
1436209807Sadrianstatic int
1437289476Sadrianarge_mbuf_chain_is_tx_aligned(struct arge_softc *sc, struct mbuf *m0)
1438209807Sadrian{
1439209807Sadrian	struct mbuf *m;
1440209807Sadrian
1441209807Sadrian	for (m = m0; m != NULL; m = m->m_next) {
1442289476Sadrian		/*
1443289476Sadrian		 * Only do this for chips that require it.
1444289476Sadrian		 */
1445289476Sadrian		if ((sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE) &&
1446289476Sadrian		    (mtod(m, intptr_t) & 3) != 0) {
1447289476Sadrian			sc->stats.tx_pkts_unaligned_start++;
1448209807Sadrian			return 0;
1449289476Sadrian		}
1450289476Sadrian
1451289476Sadrian		/*
1452289476Sadrian		 * All chips have this requirement for length.
1453289476Sadrian		 */
1454289476Sadrian		if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0)) {
1455289476Sadrian			sc->stats.tx_pkts_unaligned_len++;
1456209807Sadrian			return 0;
1457289476Sadrian		}
1458209807Sadrian	}
1459209807Sadrian	return 1;
1460209807Sadrian}
1461209807Sadrian
1462209807Sadrian/*
1463188808Sgonzo * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
1464188808Sgonzo * pointers to the fragment pointers.
1465188808Sgonzo */
1466188808Sgonzostatic int
1467188808Sgonzoarge_encap(struct arge_softc *sc, struct mbuf **m_head)
1468188808Sgonzo{
1469188808Sgonzo	struct arge_txdesc	*txd;
1470188808Sgonzo	struct arge_desc	*desc, *prev_desc;
1471188808Sgonzo	bus_dma_segment_t	txsegs[ARGE_MAXFRAGS];
1472192569Sdwhite	int			error, i, nsegs, prod, prev_prod;
1473192783Sgonzo	struct mbuf		*m;
1474188808Sgonzo
1475188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1476188808Sgonzo
1477192783Sgonzo	/*
1478289476Sadrian	 * Fix mbuf chain based on hardware alignment constraints.
1479192783Sgonzo	 */
1480192783Sgonzo	m = *m_head;
1481289476Sadrian	if (! arge_mbuf_chain_is_tx_aligned(sc, m)) {
1482209809Sadrian		sc->stats.tx_pkts_unaligned++;
1483243882Sglebius		m = m_defrag(*m_head, M_NOWAIT);
1484192783Sgonzo		if (m == NULL) {
1485192783Sgonzo			*m_head = NULL;
1486192783Sgonzo			return (ENOBUFS);
1487192783Sgonzo		}
1488192783Sgonzo		*m_head = m;
1489209809Sadrian	} else
1490209809Sadrian		sc->stats.tx_pkts_aligned++;
1491192783Sgonzo
1492188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
1493188808Sgonzo	txd = &sc->arge_cdata.arge_txdesc[prod];
1494232627Sray	error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag,
1495188808Sgonzo	    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
1496188808Sgonzo
1497188808Sgonzo	if (error == EFBIG) {
1498188808Sgonzo		panic("EFBIG");
1499188808Sgonzo	} else if (error != 0)
1500188808Sgonzo		return (error);
1501188808Sgonzo
1502188808Sgonzo	if (nsegs == 0) {
1503188808Sgonzo		m_freem(*m_head);
1504188808Sgonzo		*m_head = NULL;
1505188808Sgonzo		return (EIO);
1506188808Sgonzo	}
1507188808Sgonzo
1508188808Sgonzo	/* Check number of available descriptors. */
1509290211Sadrian	if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 2)) {
1510188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
1511289476Sadrian		sc->stats.tx_pkts_nosegs++;
1512188808Sgonzo		return (ENOBUFS);
1513188808Sgonzo	}
1514188808Sgonzo
1515188808Sgonzo	txd->tx_m = *m_head;
1516188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
1517188808Sgonzo	    BUS_DMASYNC_PREWRITE);
1518188808Sgonzo
1519232627Sray	/*
1520188808Sgonzo	 * Make a list of descriptors for this packet. DMA controller will
1521188808Sgonzo	 * walk through it while arge_link is not zero.
1522290215Sadrian	 *
1523290215Sadrian	 * Since we're in a endless circular buffer, ensure that
1524290215Sadrian	 * the first descriptor in a multi-descriptor ring is always
1525290215Sadrian	 * set to EMPTY, then un-do it when we're done populating.
1526188808Sgonzo	 */
1527188808Sgonzo	prev_prod = prod;
1528188808Sgonzo	desc = prev_desc = NULL;
1529188808Sgonzo	for (i = 0; i < nsegs; i++) {
1530290215Sadrian		uint32_t tmp;
1531290215Sadrian
1532188808Sgonzo		desc = &sc->arge_rdata.arge_tx_ring[prod];
1533188808Sgonzo
1534290215Sadrian		/*
1535290215Sadrian		 * Set DESC_EMPTY so the hardware (hopefully) stops at this
1536290215Sadrian		 * point.  We don't want it to start transmitting descriptors
1537290215Sadrian		 * before we've finished fleshing this out.
1538290215Sadrian		 */
1539290215Sadrian		tmp = ARGE_DMASIZE(txsegs[i].ds_len);
1540290215Sadrian		if (i == 0)
1541290215Sadrian			tmp |= ARGE_DESC_EMPTY;
1542290215Sadrian		desc->packet_ctrl = tmp;
1543290215Sadrian
1544289476Sadrian		/* XXX Note: only relevant for older MACs; but check length! */
1545289476Sadrian		if ((sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE) &&
1546289476Sadrian		    (txsegs[i].ds_addr & 3))
1547192783Sgonzo			panic("TX packet address unaligned\n");
1548192783Sgonzo
1549188808Sgonzo		desc->packet_addr = txsegs[i].ds_addr;
1550232627Sray
1551188808Sgonzo		/* link with previous descriptor */
1552188808Sgonzo		if (prev_desc)
1553188808Sgonzo			prev_desc->packet_ctrl |= ARGE_DESC_MORE;
1554188808Sgonzo
1555188808Sgonzo		sc->arge_cdata.arge_tx_cnt++;
1556188808Sgonzo		prev_desc = desc;
1557188808Sgonzo		ARGE_INC(prod, ARGE_TX_RING_COUNT);
1558188808Sgonzo	}
1559188808Sgonzo
1560188808Sgonzo	/* Update producer index. */
1561188808Sgonzo	sc->arge_cdata.arge_tx_prod = prod;
1562188808Sgonzo
1563290215Sadrian	/*
1564290215Sadrian	 * The descriptors are updated, so enable the first one.
1565290215Sadrian	 */
1566290215Sadrian	desc = &sc->arge_rdata.arge_tx_ring[prev_prod];
1567290215Sadrian	desc->packet_ctrl &= ~ ARGE_DESC_EMPTY;
1568290215Sadrian
1569188808Sgonzo	/* Sync descriptors. */
1570188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1571188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1572188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1573188808Sgonzo
1574290213Sadrian	/* Flush writes */
1575290213Sadrian	ARGE_BARRIER_WRITE(sc);
1576290213Sadrian
1577188808Sgonzo	/* Start transmitting */
1578232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: setting DMA_TX_CONTROL_EN\n",
1579232628Sray	    __func__);
1580188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN);
1581188808Sgonzo	return (0);
1582188808Sgonzo}
1583188808Sgonzo
1584188808Sgonzostatic void
1585188808Sgonzoarge_start(struct ifnet *ifp)
1586188808Sgonzo{
1587188808Sgonzo	struct arge_softc	 *sc;
1588188808Sgonzo
1589188808Sgonzo	sc = ifp->if_softc;
1590188808Sgonzo
1591188808Sgonzo	ARGE_LOCK(sc);
1592188808Sgonzo	arge_start_locked(ifp);
1593188808Sgonzo	ARGE_UNLOCK(sc);
1594188808Sgonzo}
1595188808Sgonzo
1596188808Sgonzostatic void
1597188808Sgonzoarge_start_locked(struct ifnet *ifp)
1598188808Sgonzo{
1599188808Sgonzo	struct arge_softc	*sc;
1600188808Sgonzo	struct mbuf		*m_head;
1601220356Sadrian	int			enq = 0;
1602188808Sgonzo
1603188808Sgonzo	sc = ifp->if_softc;
1604188808Sgonzo
1605188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1606188808Sgonzo
1607220356Sadrian	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: beginning\n", __func__);
1608220356Sadrian
1609188808Sgonzo	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1610188808Sgonzo	    IFF_DRV_RUNNING || sc->arge_link_status == 0 )
1611188808Sgonzo		return;
1612188808Sgonzo
1613220356Sadrian	/*
1614220356Sadrian	 * Before we go any further, check whether we're already full.
1615220356Sadrian	 * The below check errors out immediately if the ring is full
1616220356Sadrian	 * and never gets a chance to set this flag. Although it's
1617220356Sadrian	 * likely never needed, this at least avoids an unexpected
1618220356Sadrian	 * situation.
1619220356Sadrian	 */
1620220356Sadrian	if (sc->arge_cdata.arge_tx_cnt >= ARGE_TX_RING_COUNT - 2) {
1621220356Sadrian		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1622232628Sray		ARGEDEBUG(sc, ARGE_DBG_ERR,
1623232628Sray		    "%s: tx_cnt %d >= max %d; setting IFF_DRV_OACTIVE\n",
1624232628Sray		    __func__, sc->arge_cdata.arge_tx_cnt,
1625232628Sray		    ARGE_TX_RING_COUNT - 2);
1626220356Sadrian		return;
1627220356Sadrian	}
1628220356Sadrian
1629188808Sgonzo	arge_flush_ddr(sc);
1630188808Sgonzo
1631188808Sgonzo	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
1632188808Sgonzo	    sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) {
1633188808Sgonzo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
1634188808Sgonzo		if (m_head == NULL)
1635188808Sgonzo			break;
1636188808Sgonzo
1637188808Sgonzo
1638188808Sgonzo		/*
1639188808Sgonzo		 * Pack the data into the transmit ring.
1640188808Sgonzo		 */
1641188808Sgonzo		if (arge_encap(sc, &m_head)) {
1642188808Sgonzo			if (m_head == NULL)
1643188808Sgonzo				break;
1644188808Sgonzo			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1645188808Sgonzo			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1646188808Sgonzo			break;
1647188808Sgonzo		}
1648188808Sgonzo
1649188808Sgonzo		enq++;
1650188808Sgonzo		/*
1651188808Sgonzo		 * If there's a BPF listener, bounce a copy of this frame
1652188808Sgonzo		 * to him.
1653188808Sgonzo		 */
1654188808Sgonzo		ETHER_BPF_MTAP(ifp, m_head);
1655188808Sgonzo	}
1656232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: finished; queued %d packets\n",
1657232628Sray	    __func__, enq);
1658188808Sgonzo}
1659188808Sgonzo
1660188808Sgonzostatic void
1661188808Sgonzoarge_stop(struct arge_softc *sc)
1662188808Sgonzo{
1663188808Sgonzo	struct ifnet	    *ifp;
1664188808Sgonzo
1665188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1666188808Sgonzo
1667188808Sgonzo	ifp = sc->arge_ifp;
1668188808Sgonzo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1669199234Sgonzo	if (sc->arge_miibus)
1670199234Sgonzo		callout_stop(&sc->arge_stat_callout);
1671188808Sgonzo
1672188808Sgonzo	/* mask out interrupts */
1673188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1674188808Sgonzo
1675188808Sgonzo	arge_reset_dma(sc);
1676232912Sadrian
1677232912Sadrian	/* Flush FIFO and free any existing mbufs */
1678232912Sadrian	arge_flush_ddr(sc);
1679232912Sadrian	arge_rx_ring_free(sc);
1680255300Sloos	arge_tx_ring_free(sc);
1681188808Sgonzo}
1682188808Sgonzo
1683188808Sgonzo
1684188808Sgonzostatic int
1685188808Sgonzoarge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1686188808Sgonzo{
1687188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1688188808Sgonzo	struct ifreq		*ifr = (struct ifreq *) data;
1689188808Sgonzo	struct mii_data		*mii;
1690188808Sgonzo	int			error;
1691192783Sgonzo#ifdef DEVICE_POLLING
1692192783Sgonzo	int			mask;
1693192783Sgonzo#endif
1694188808Sgonzo
1695188808Sgonzo	switch (command) {
1696188808Sgonzo	case SIOCSIFFLAGS:
1697198932Sgonzo		ARGE_LOCK(sc);
1698198932Sgonzo		if ((ifp->if_flags & IFF_UP) != 0) {
1699198932Sgonzo			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1700198932Sgonzo				if (((ifp->if_flags ^ sc->arge_if_flags)
1701198939Sgonzo				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0) {
1702198939Sgonzo					/* XXX: handle promisc & multi flags */
1703198939Sgonzo				}
1704232627Sray
1705198932Sgonzo			} else {
1706198932Sgonzo				if (!sc->arge_detach)
1707198932Sgonzo					arge_init_locked(sc);
1708198932Sgonzo			}
1709198932Sgonzo		} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1710198932Sgonzo			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1711198932Sgonzo			arge_stop(sc);
1712198932Sgonzo		}
1713198932Sgonzo		sc->arge_if_flags = ifp->if_flags;
1714198932Sgonzo		ARGE_UNLOCK(sc);
1715188808Sgonzo		error = 0;
1716188808Sgonzo		break;
1717188808Sgonzo	case SIOCADDMULTI:
1718188808Sgonzo	case SIOCDELMULTI:
1719198932Sgonzo		/* XXX: implement SIOCDELMULTI */
1720188808Sgonzo		error = 0;
1721188808Sgonzo		break;
1722188808Sgonzo	case SIOCGIFMEDIA:
1723188808Sgonzo	case SIOCSIFMEDIA:
1724199234Sgonzo		if (sc->arge_miibus) {
1725199234Sgonzo			mii = device_get_softc(sc->arge_miibus);
1726232628Sray			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
1727232628Sray			    command);
1728199234Sgonzo		}
1729232627Sray		else
1730232628Sray			error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia,
1731232628Sray			    command);
1732188808Sgonzo		break;
1733198933Sgonzo	case SIOCSIFCAP:
1734198932Sgonzo		/* XXX: Check other capabilities */
1735192783Sgonzo#ifdef DEVICE_POLLING
1736198933Sgonzo		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
1737198933Sgonzo		if (mask & IFCAP_POLLING) {
1738198933Sgonzo			if (ifr->ifr_reqcap & IFCAP_POLLING) {
1739192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1740198933Sgonzo				error = ether_poll_register(arge_poll, ifp);
1741198933Sgonzo				if (error)
1742198933Sgonzo					return error;
1743198933Sgonzo				ARGE_LOCK(sc);
1744198933Sgonzo				ifp->if_capenable |= IFCAP_POLLING;
1745198933Sgonzo				ARGE_UNLOCK(sc);
1746198933Sgonzo			} else {
1747192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1748198933Sgonzo				error = ether_poll_deregister(ifp);
1749198933Sgonzo				ARGE_LOCK(sc);
1750198933Sgonzo				ifp->if_capenable &= ~IFCAP_POLLING;
1751198933Sgonzo				ARGE_UNLOCK(sc);
1752198933Sgonzo			}
1753198933Sgonzo		}
1754198932Sgonzo		error = 0;
1755198933Sgonzo		break;
1756192783Sgonzo#endif
1757188808Sgonzo	default:
1758188808Sgonzo		error = ether_ioctl(ifp, command, data);
1759188808Sgonzo		break;
1760188808Sgonzo	}
1761188808Sgonzo
1762188808Sgonzo	return (error);
1763188808Sgonzo}
1764188808Sgonzo
1765188808Sgonzo/*
1766188808Sgonzo * Set media options.
1767188808Sgonzo */
1768188808Sgonzostatic int
1769188808Sgonzoarge_ifmedia_upd(struct ifnet *ifp)
1770188808Sgonzo{
1771188808Sgonzo	struct arge_softc		*sc;
1772188808Sgonzo	struct mii_data		*mii;
1773188808Sgonzo	struct mii_softc	*miisc;
1774188808Sgonzo	int			error;
1775188808Sgonzo
1776188808Sgonzo	sc = ifp->if_softc;
1777188808Sgonzo	ARGE_LOCK(sc);
1778188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1779221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1780221407Smarius		PHY_RESET(miisc);
1781188808Sgonzo	error = mii_mediachg(mii);
1782188808Sgonzo	ARGE_UNLOCK(sc);
1783188808Sgonzo
1784188808Sgonzo	return (error);
1785188808Sgonzo}
1786188808Sgonzo
1787188808Sgonzo/*
1788188808Sgonzo * Report current media status.
1789188808Sgonzo */
1790188808Sgonzostatic void
1791188808Sgonzoarge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1792188808Sgonzo{
1793188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1794188808Sgonzo	struct mii_data		*mii;
1795188808Sgonzo
1796188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1797188808Sgonzo	ARGE_LOCK(sc);
1798188808Sgonzo	mii_pollstat(mii);
1799188808Sgonzo	ifmr->ifm_active = mii->mii_media_active;
1800188808Sgonzo	ifmr->ifm_status = mii->mii_media_status;
1801226478Syongari	ARGE_UNLOCK(sc);
1802188808Sgonzo}
1803188808Sgonzo
1804188808Sgonzostruct arge_dmamap_arg {
1805188808Sgonzo	bus_addr_t	arge_busaddr;
1806188808Sgonzo};
1807188808Sgonzo
1808188808Sgonzostatic void
1809188808Sgonzoarge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1810188808Sgonzo{
1811188808Sgonzo	struct arge_dmamap_arg	*ctx;
1812188808Sgonzo
1813188808Sgonzo	if (error != 0)
1814188808Sgonzo		return;
1815188808Sgonzo	ctx = arg;
1816188808Sgonzo	ctx->arge_busaddr = segs[0].ds_addr;
1817188808Sgonzo}
1818188808Sgonzo
1819188808Sgonzostatic int
1820188808Sgonzoarge_dma_alloc(struct arge_softc *sc)
1821188808Sgonzo{
1822188808Sgonzo	struct arge_dmamap_arg	ctx;
1823188808Sgonzo	struct arge_txdesc	*txd;
1824188808Sgonzo	struct arge_rxdesc	*rxd;
1825188808Sgonzo	int			error, i;
1826289476Sadrian	int			arge_tx_align, arge_rx_align;
1827188808Sgonzo
1828289476Sadrian	/* Assume 4 byte alignment by default */
1829289476Sadrian	arge_tx_align = 4;
1830289476Sadrian	arge_rx_align = 4;
1831289476Sadrian
1832289476Sadrian	if (sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE)
1833289476Sadrian		arge_tx_align = 1;
1834289476Sadrian	if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE)
1835289476Sadrian		arge_rx_align = 1;
1836289476Sadrian
1837188808Sgonzo	/* Create parent DMA tag. */
1838188808Sgonzo	error = bus_dma_tag_create(
1839188808Sgonzo	    bus_get_dma_tag(sc->arge_dev),	/* parent */
1840188808Sgonzo	    1, 0,			/* alignment, boundary */
1841188808Sgonzo	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1842188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1843188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1844188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
1845188808Sgonzo	    0,				/* nsegments */
1846188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1847188808Sgonzo	    0,				/* flags */
1848188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1849188808Sgonzo	    &sc->arge_cdata.arge_parent_tag);
1850188808Sgonzo	if (error != 0) {
1851232628Sray		device_printf(sc->arge_dev,
1852232628Sray		    "failed to create parent DMA tag\n");
1853188808Sgonzo		goto fail;
1854188808Sgonzo	}
1855188808Sgonzo	/* Create tag for Tx ring. */
1856188808Sgonzo	error = bus_dma_tag_create(
1857188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1858188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1859188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1860188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1861188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1862188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsize */
1863188808Sgonzo	    1,				/* nsegments */
1864188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsegsize */
1865188808Sgonzo	    0,				/* flags */
1866188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1867188808Sgonzo	    &sc->arge_cdata.arge_tx_ring_tag);
1868188808Sgonzo	if (error != 0) {
1869232628Sray		device_printf(sc->arge_dev,
1870232628Sray		    "failed to create Tx ring DMA tag\n");
1871188808Sgonzo		goto fail;
1872188808Sgonzo	}
1873188808Sgonzo
1874188808Sgonzo	/* Create tag for Rx ring. */
1875188808Sgonzo	error = bus_dma_tag_create(
1876188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1877188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1878188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1879188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1880188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1881188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsize */
1882188808Sgonzo	    1,				/* nsegments */
1883188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsegsize */
1884188808Sgonzo	    0,				/* flags */
1885188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1886188808Sgonzo	    &sc->arge_cdata.arge_rx_ring_tag);
1887188808Sgonzo	if (error != 0) {
1888232628Sray		device_printf(sc->arge_dev,
1889232628Sray		    "failed to create Rx ring DMA tag\n");
1890188808Sgonzo		goto fail;
1891188808Sgonzo	}
1892188808Sgonzo
1893188808Sgonzo	/* Create tag for Tx buffers. */
1894188808Sgonzo	error = bus_dma_tag_create(
1895188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1896289476Sadrian	    arge_tx_align, 0,		/* alignment, boundary */
1897188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1898188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1899188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1900188808Sgonzo	    MCLBYTES * ARGE_MAXFRAGS,	/* maxsize */
1901188808Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1902188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1903188808Sgonzo	    0,				/* flags */
1904188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1905188808Sgonzo	    &sc->arge_cdata.arge_tx_tag);
1906188808Sgonzo	if (error != 0) {
1907188808Sgonzo		device_printf(sc->arge_dev, "failed to create Tx DMA tag\n");
1908188808Sgonzo		goto fail;
1909188808Sgonzo	}
1910188808Sgonzo
1911188808Sgonzo	/* Create tag for Rx buffers. */
1912188808Sgonzo	error = bus_dma_tag_create(
1913188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1914289476Sadrian	    arge_rx_align, 0,		/* alignment, boundary */
1915188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1916188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1917188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1918188808Sgonzo	    MCLBYTES,			/* maxsize */
1919192821Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1920188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1921188808Sgonzo	    0,				/* flags */
1922188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1923188808Sgonzo	    &sc->arge_cdata.arge_rx_tag);
1924188808Sgonzo	if (error != 0) {
1925188808Sgonzo		device_printf(sc->arge_dev, "failed to create Rx DMA tag\n");
1926188808Sgonzo		goto fail;
1927188808Sgonzo	}
1928188808Sgonzo
1929188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
1930188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag,
1931188808Sgonzo	    (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK |
1932232628Sray	    BUS_DMA_COHERENT | BUS_DMA_ZERO,
1933232628Sray	    &sc->arge_cdata.arge_tx_ring_map);
1934188808Sgonzo	if (error != 0) {
1935188808Sgonzo		device_printf(sc->arge_dev,
1936188808Sgonzo		    "failed to allocate DMA'able memory for Tx ring\n");
1937188808Sgonzo		goto fail;
1938188808Sgonzo	}
1939188808Sgonzo
1940188808Sgonzo	ctx.arge_busaddr = 0;
1941188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag,
1942188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring,
1943188808Sgonzo	    ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1944188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1945188808Sgonzo		device_printf(sc->arge_dev,
1946188808Sgonzo		    "failed to load DMA'able memory for Tx ring\n");
1947188808Sgonzo		goto fail;
1948188808Sgonzo	}
1949188808Sgonzo	sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr;
1950188808Sgonzo
1951188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
1952188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag,
1953188808Sgonzo	    (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK |
1954232628Sray	    BUS_DMA_COHERENT | BUS_DMA_ZERO,
1955232628Sray	    &sc->arge_cdata.arge_rx_ring_map);
1956188808Sgonzo	if (error != 0) {
1957188808Sgonzo		device_printf(sc->arge_dev,
1958188808Sgonzo		    "failed to allocate DMA'able memory for Rx ring\n");
1959188808Sgonzo		goto fail;
1960188808Sgonzo	}
1961188808Sgonzo
1962188808Sgonzo	ctx.arge_busaddr = 0;
1963188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag,
1964188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring,
1965188808Sgonzo	    ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1966188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1967188808Sgonzo		device_printf(sc->arge_dev,
1968188808Sgonzo		    "failed to load DMA'able memory for Rx ring\n");
1969188808Sgonzo		goto fail;
1970188808Sgonzo	}
1971188808Sgonzo	sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr;
1972188808Sgonzo
1973188808Sgonzo	/* Create DMA maps for Tx buffers. */
1974188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
1975188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
1976188808Sgonzo		txd->tx_m = NULL;
1977188808Sgonzo		txd->tx_dmamap = NULL;
1978188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0,
1979188808Sgonzo		    &txd->tx_dmamap);
1980188808Sgonzo		if (error != 0) {
1981188808Sgonzo			device_printf(sc->arge_dev,
1982188808Sgonzo			    "failed to create Tx dmamap\n");
1983188808Sgonzo			goto fail;
1984188808Sgonzo		}
1985188808Sgonzo	}
1986188808Sgonzo	/* Create DMA maps for Rx buffers. */
1987188808Sgonzo	if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
1988188808Sgonzo	    &sc->arge_cdata.arge_rx_sparemap)) != 0) {
1989188808Sgonzo		device_printf(sc->arge_dev,
1990188808Sgonzo		    "failed to create spare Rx dmamap\n");
1991188808Sgonzo		goto fail;
1992188808Sgonzo	}
1993188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
1994188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
1995188808Sgonzo		rxd->rx_m = NULL;
1996188808Sgonzo		rxd->rx_dmamap = NULL;
1997188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
1998188808Sgonzo		    &rxd->rx_dmamap);
1999188808Sgonzo		if (error != 0) {
2000188808Sgonzo			device_printf(sc->arge_dev,
2001188808Sgonzo			    "failed to create Rx dmamap\n");
2002188808Sgonzo			goto fail;
2003188808Sgonzo		}
2004188808Sgonzo	}
2005188808Sgonzo
2006188808Sgonzofail:
2007188808Sgonzo	return (error);
2008188808Sgonzo}
2009188808Sgonzo
2010188808Sgonzostatic void
2011188808Sgonzoarge_dma_free(struct arge_softc *sc)
2012188808Sgonzo{
2013188808Sgonzo	struct arge_txdesc	*txd;
2014188808Sgonzo	struct arge_rxdesc	*rxd;
2015188808Sgonzo	int			i;
2016188808Sgonzo
2017188808Sgonzo	/* Tx ring. */
2018188808Sgonzo	if (sc->arge_cdata.arge_tx_ring_tag) {
2019267363Sjhb		if (sc->arge_rdata.arge_tx_ring_paddr)
2020188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag,
2021188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
2022267363Sjhb		if (sc->arge_rdata.arge_tx_ring)
2023188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag,
2024188808Sgonzo			    sc->arge_rdata.arge_tx_ring,
2025188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
2026188808Sgonzo		sc->arge_rdata.arge_tx_ring = NULL;
2027267363Sjhb		sc->arge_rdata.arge_tx_ring_paddr = 0;
2028188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag);
2029188808Sgonzo		sc->arge_cdata.arge_tx_ring_tag = NULL;
2030188808Sgonzo	}
2031188808Sgonzo	/* Rx ring. */
2032188808Sgonzo	if (sc->arge_cdata.arge_rx_ring_tag) {
2033267363Sjhb		if (sc->arge_rdata.arge_rx_ring_paddr)
2034188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag,
2035188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
2036267363Sjhb		if (sc->arge_rdata.arge_rx_ring)
2037188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag,
2038188808Sgonzo			    sc->arge_rdata.arge_rx_ring,
2039188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
2040188808Sgonzo		sc->arge_rdata.arge_rx_ring = NULL;
2041267363Sjhb		sc->arge_rdata.arge_rx_ring_paddr = 0;
2042188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag);
2043188808Sgonzo		sc->arge_cdata.arge_rx_ring_tag = NULL;
2044188808Sgonzo	}
2045188808Sgonzo	/* Tx buffers. */
2046188808Sgonzo	if (sc->arge_cdata.arge_tx_tag) {
2047188808Sgonzo		for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2048188808Sgonzo			txd = &sc->arge_cdata.arge_txdesc[i];
2049188808Sgonzo			if (txd->tx_dmamap) {
2050188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag,
2051188808Sgonzo				    txd->tx_dmamap);
2052188808Sgonzo				txd->tx_dmamap = NULL;
2053188808Sgonzo			}
2054188808Sgonzo		}
2055188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag);
2056188808Sgonzo		sc->arge_cdata.arge_tx_tag = NULL;
2057188808Sgonzo	}
2058188808Sgonzo	/* Rx buffers. */
2059188808Sgonzo	if (sc->arge_cdata.arge_rx_tag) {
2060188808Sgonzo		for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2061188808Sgonzo			rxd = &sc->arge_cdata.arge_rxdesc[i];
2062188808Sgonzo			if (rxd->rx_dmamap) {
2063188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
2064188808Sgonzo				    rxd->rx_dmamap);
2065188808Sgonzo				rxd->rx_dmamap = NULL;
2066188808Sgonzo			}
2067188808Sgonzo		}
2068188808Sgonzo		if (sc->arge_cdata.arge_rx_sparemap) {
2069188808Sgonzo			bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
2070188808Sgonzo			    sc->arge_cdata.arge_rx_sparemap);
2071188808Sgonzo			sc->arge_cdata.arge_rx_sparemap = 0;
2072188808Sgonzo		}
2073188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag);
2074188808Sgonzo		sc->arge_cdata.arge_rx_tag = NULL;
2075188808Sgonzo	}
2076188808Sgonzo
2077188808Sgonzo	if (sc->arge_cdata.arge_parent_tag) {
2078188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag);
2079188808Sgonzo		sc->arge_cdata.arge_parent_tag = NULL;
2080188808Sgonzo	}
2081188808Sgonzo}
2082188808Sgonzo
2083188808Sgonzo/*
2084188808Sgonzo * Initialize the transmit descriptors.
2085188808Sgonzo */
2086188808Sgonzostatic int
2087188808Sgonzoarge_tx_ring_init(struct arge_softc *sc)
2088188808Sgonzo{
2089188808Sgonzo	struct arge_ring_data	*rd;
2090188808Sgonzo	struct arge_txdesc	*txd;
2091188808Sgonzo	bus_addr_t		addr;
2092188808Sgonzo	int			i;
2093188808Sgonzo
2094188808Sgonzo	sc->arge_cdata.arge_tx_prod = 0;
2095188808Sgonzo	sc->arge_cdata.arge_tx_cons = 0;
2096188808Sgonzo	sc->arge_cdata.arge_tx_cnt = 0;
2097188808Sgonzo
2098188808Sgonzo	rd = &sc->arge_rdata;
2099188808Sgonzo	bzero(rd->arge_tx_ring, sizeof(rd->arge_tx_ring));
2100188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2101188808Sgonzo		if (i == ARGE_TX_RING_COUNT - 1)
2102188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, 0);
2103188808Sgonzo		else
2104188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, i + 1);
2105188808Sgonzo		rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY;
2106188808Sgonzo		rd->arge_tx_ring[i].next_desc = addr;
2107188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
2108188808Sgonzo		txd->tx_m = NULL;
2109188808Sgonzo	}
2110188808Sgonzo
2111188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
2112188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
2113188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2114188808Sgonzo
2115188808Sgonzo	return (0);
2116188808Sgonzo}
2117188808Sgonzo
2118188808Sgonzo/*
2119255300Sloos * Free the Tx ring, unload any pending dma transaction and free the mbuf.
2120255300Sloos */
2121255300Sloosstatic void
2122255300Sloosarge_tx_ring_free(struct arge_softc *sc)
2123255300Sloos{
2124255300Sloos	struct arge_txdesc	*txd;
2125255300Sloos	int			i;
2126255300Sloos
2127255300Sloos	/* Free the Tx buffers. */
2128255300Sloos	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2129255300Sloos		txd = &sc->arge_cdata.arge_txdesc[i];
2130255300Sloos		if (txd->tx_dmamap) {
2131255300Sloos			bus_dmamap_sync(sc->arge_cdata.arge_tx_tag,
2132255300Sloos			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
2133255300Sloos			bus_dmamap_unload(sc->arge_cdata.arge_tx_tag,
2134255300Sloos			    txd->tx_dmamap);
2135255300Sloos		}
2136255300Sloos		if (txd->tx_m)
2137255300Sloos			m_freem(txd->tx_m);
2138255300Sloos		txd->tx_m = NULL;
2139255300Sloos	}
2140255300Sloos}
2141255300Sloos
2142255300Sloos/*
2143188808Sgonzo * Initialize the RX descriptors and allocate mbufs for them. Note that
2144188808Sgonzo * we arrange the descriptors in a closed ring, so that the last descriptor
2145188808Sgonzo * points back to the first.
2146188808Sgonzo */
2147188808Sgonzostatic int
2148188808Sgonzoarge_rx_ring_init(struct arge_softc *sc)
2149188808Sgonzo{
2150188808Sgonzo	struct arge_ring_data	*rd;
2151188808Sgonzo	struct arge_rxdesc	*rxd;
2152188808Sgonzo	bus_addr_t		addr;
2153188808Sgonzo	int			i;
2154188808Sgonzo
2155188808Sgonzo	sc->arge_cdata.arge_rx_cons = 0;
2156188808Sgonzo
2157188808Sgonzo	rd = &sc->arge_rdata;
2158188808Sgonzo	bzero(rd->arge_rx_ring, sizeof(rd->arge_rx_ring));
2159188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2160188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
2161232912Sadrian		if (rxd->rx_m != NULL) {
2162232912Sadrian			device_printf(sc->arge_dev,
2163232912Sadrian			    "%s: ring[%d] rx_m wasn't free?\n",
2164232912Sadrian			    __func__,
2165232912Sadrian			    i);
2166232912Sadrian		}
2167188808Sgonzo		rxd->rx_m = NULL;
2168188808Sgonzo		rxd->desc = &rd->arge_rx_ring[i];
2169188808Sgonzo		if (i == ARGE_RX_RING_COUNT - 1)
2170188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, 0);
2171188808Sgonzo		else
2172188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, i + 1);
2173188808Sgonzo		rd->arge_rx_ring[i].next_desc = addr;
2174192783Sgonzo		if (arge_newbuf(sc, i) != 0) {
2175188808Sgonzo			return (ENOBUFS);
2176192783Sgonzo		}
2177188808Sgonzo	}
2178188808Sgonzo
2179188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2180188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
2181195434Sgonzo	    BUS_DMASYNC_PREWRITE);
2182188808Sgonzo
2183188808Sgonzo	return (0);
2184188808Sgonzo}
2185188808Sgonzo
2186188808Sgonzo/*
2187232912Sadrian * Free all the buffers in the RX ring.
2188232912Sadrian *
2189232912Sadrian * TODO: ensure that DMA is disabled and no pending DMA
2190232912Sadrian * is lurking in the FIFO.
2191232912Sadrian */
2192232912Sadrianstatic void
2193232912Sadrianarge_rx_ring_free(struct arge_softc *sc)
2194232912Sadrian{
2195232912Sadrian	int i;
2196232912Sadrian	struct arge_rxdesc	*rxd;
2197232912Sadrian
2198232912Sadrian	ARGE_LOCK_ASSERT(sc);
2199232912Sadrian
2200232912Sadrian	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2201232912Sadrian		rxd = &sc->arge_cdata.arge_rxdesc[i];
2202232912Sadrian		/* Unmap the mbuf */
2203232912Sadrian		if (rxd->rx_m != NULL) {
2204232912Sadrian			bus_dmamap_unload(sc->arge_cdata.arge_rx_tag,
2205232912Sadrian			    rxd->rx_dmamap);
2206232912Sadrian			m_free(rxd->rx_m);
2207232912Sadrian			rxd->rx_m = NULL;
2208232912Sadrian		}
2209232912Sadrian	}
2210232912Sadrian}
2211232912Sadrian
2212232912Sadrian/*
2213188808Sgonzo * Initialize an RX descriptor and attach an MBUF cluster.
2214188808Sgonzo */
2215188808Sgonzostatic int
2216188808Sgonzoarge_newbuf(struct arge_softc *sc, int idx)
2217188808Sgonzo{
2218188808Sgonzo	struct arge_desc		*desc;
2219188808Sgonzo	struct arge_rxdesc	*rxd;
2220188808Sgonzo	struct mbuf		*m;
2221188808Sgonzo	bus_dma_segment_t	segs[1];
2222188808Sgonzo	bus_dmamap_t		map;
2223188808Sgonzo	int			nsegs;
2224188808Sgonzo
2225289671Sadrian	/* XXX TODO: should just allocate an explicit 2KiB buffer */
2226243882Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2227188808Sgonzo	if (m == NULL)
2228188808Sgonzo		return (ENOBUFS);
2229188808Sgonzo	m->m_len = m->m_pkthdr.len = MCLBYTES;
2230289476Sadrian
2231289476Sadrian	/*
2232289476Sadrian	 * Add extra space to "adjust" (copy) the packet back to be aligned
2233289476Sadrian	 * for purposes of IPv4/IPv6 header contents.
2234289476Sadrian	 */
2235289671Sadrian	if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE)
2236289671Sadrian		m_adj(m, sizeof(uint64_t));
2237289671Sadrian	/*
2238289671Sadrian	 * If it's a 1-byte aligned buffer, then just offset it two bytes
2239289671Sadrian	 * and that will give us a hopefully correctly DWORD aligned
2240289671Sadrian	 * L3 payload - and we won't have to undo it afterwards.
2241289671Sadrian	 */
2242289671Sadrian	else if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE)
2243289671Sadrian		m_adj(m, sizeof(uint16_t));
2244188808Sgonzo
2245188808Sgonzo	if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag,
2246188808Sgonzo	    sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) {
2247188808Sgonzo		m_freem(m);
2248188808Sgonzo		return (ENOBUFS);
2249188808Sgonzo	}
2250188808Sgonzo	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2251188808Sgonzo
2252188808Sgonzo	rxd = &sc->arge_cdata.arge_rxdesc[idx];
2253188808Sgonzo	if (rxd->rx_m != NULL) {
2254188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap);
2255188808Sgonzo	}
2256188808Sgonzo	map = rxd->rx_dmamap;
2257188808Sgonzo	rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap;
2258188808Sgonzo	sc->arge_cdata.arge_rx_sparemap = map;
2259188808Sgonzo	rxd->rx_m = m;
2260188808Sgonzo	desc = rxd->desc;
2261289476Sadrian	if ((sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE) &&
2262289476Sadrian	    segs[0].ds_addr & 3)
2263192783Sgonzo		panic("RX packet address unaligned");
2264188808Sgonzo	desc->packet_addr = segs[0].ds_addr;
2265192783Sgonzo	desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len);
2266188808Sgonzo
2267195434Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2268195434Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
2269195434Sgonzo	    BUS_DMASYNC_PREWRITE);
2270195434Sgonzo
2271188808Sgonzo	return (0);
2272188808Sgonzo}
2273188808Sgonzo
2274289671Sadrian/*
2275289671Sadrian * Move the data backwards 16 bits to (hopefully!) ensure the
2276289671Sadrian * IPv4/IPv6 payload is aligned.
2277289671Sadrian *
2278289671Sadrian * This is required for earlier hardware where the RX path
2279289671Sadrian * requires DWORD aligned buffers.
2280289671Sadrian */
2281188808Sgonzostatic __inline void
2282188808Sgonzoarge_fixup_rx(struct mbuf *m)
2283188808Sgonzo{
2284198933Sgonzo	int		i;
2285198933Sgonzo	uint16_t	*src, *dst;
2286188808Sgonzo
2287188808Sgonzo	src = mtod(m, uint16_t *);
2288188808Sgonzo	dst = src - 1;
2289188808Sgonzo
2290195434Sgonzo	for (i = 0; i < m->m_len / sizeof(uint16_t); i++) {
2291188808Sgonzo		*dst++ = *src++;
2292195434Sgonzo	}
2293188808Sgonzo
2294195434Sgonzo	if (m->m_len % sizeof(uint16_t))
2295195434Sgonzo		*(uint8_t *)dst = *(uint8_t *)src;
2296195434Sgonzo
2297188808Sgonzo	m->m_data -= ETHER_ALIGN;
2298188808Sgonzo}
2299188808Sgonzo
2300192783Sgonzo#ifdef DEVICE_POLLING
2301198667Sgonzostatic int
2302192783Sgonzoarge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
2303192783Sgonzo{
2304192783Sgonzo	struct arge_softc *sc = ifp->if_softc;
2305198667Sgonzo	int rx_npkts = 0;
2306188808Sgonzo
2307198933Sgonzo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2308192783Sgonzo		ARGE_LOCK(sc);
2309192783Sgonzo		arge_tx_locked(sc);
2310198667Sgonzo		rx_npkts = arge_rx_locked(sc);
2311192783Sgonzo		ARGE_UNLOCK(sc);
2312198933Sgonzo	}
2313198667Sgonzo
2314198667Sgonzo	return (rx_npkts);
2315192783Sgonzo}
2316192783Sgonzo#endif /* DEVICE_POLLING */
2317192783Sgonzo
2318192783Sgonzo
2319188808Sgonzostatic void
2320188808Sgonzoarge_tx_locked(struct arge_softc *sc)
2321188808Sgonzo{
2322188808Sgonzo	struct arge_txdesc	*txd;
2323188808Sgonzo	struct arge_desc	*cur_tx;
2324188808Sgonzo	struct ifnet		*ifp;
2325188808Sgonzo	uint32_t		ctrl;
2326188808Sgonzo	int			cons, prod;
2327188808Sgonzo
2328188808Sgonzo	ARGE_LOCK_ASSERT(sc);
2329188808Sgonzo
2330188808Sgonzo	cons = sc->arge_cdata.arge_tx_cons;
2331188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
2332220356Sadrian
2333232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: cons=%d, prod=%d\n", __func__, cons,
2334232628Sray	    prod);
2335220356Sadrian
2336188808Sgonzo	if (cons == prod)
2337188808Sgonzo		return;
2338188808Sgonzo
2339188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
2340188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
2341188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2342188808Sgonzo
2343188808Sgonzo	ifp = sc->arge_ifp;
2344188808Sgonzo	/*
2345188808Sgonzo	 * Go through our tx list and free mbufs for those
2346188808Sgonzo	 * frames that have been transmitted.
2347188808Sgonzo	 */
2348188808Sgonzo	for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) {
2349188808Sgonzo		cur_tx = &sc->arge_rdata.arge_tx_ring[cons];
2350188808Sgonzo		ctrl = cur_tx->packet_ctrl;
2351188808Sgonzo		/* Check if descriptor has "finished" flag */
2352188808Sgonzo		if ((ctrl & ARGE_DESC_EMPTY) == 0)
2353188808Sgonzo			break;
2354188808Sgonzo
2355188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
2356188808Sgonzo
2357188808Sgonzo		sc->arge_cdata.arge_tx_cnt--;
2358188808Sgonzo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2359188808Sgonzo
2360188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[cons];
2361188808Sgonzo
2362271858Sglebius		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
2363188808Sgonzo
2364188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
2365188808Sgonzo		    BUS_DMASYNC_POSTWRITE);
2366188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
2367188808Sgonzo
2368188808Sgonzo		/* Free only if it's first descriptor in list */
2369188808Sgonzo		if (txd->tx_m)
2370188808Sgonzo			m_freem(txd->tx_m);
2371188808Sgonzo		txd->tx_m = NULL;
2372188808Sgonzo
2373188808Sgonzo		/* reset descriptor */
2374188808Sgonzo		cur_tx->packet_addr = 0;
2375188808Sgonzo	}
2376188808Sgonzo
2377188808Sgonzo	sc->arge_cdata.arge_tx_cons = cons;
2378188808Sgonzo
2379188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
2380188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE);
2381188808Sgonzo}
2382188808Sgonzo
2383188808Sgonzo
2384198667Sgonzostatic int
2385188808Sgonzoarge_rx_locked(struct arge_softc *sc)
2386188808Sgonzo{
2387188808Sgonzo	struct arge_rxdesc	*rxd;
2388188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
2389192783Sgonzo	int			cons, prog, packet_len, i;
2390188808Sgonzo	struct arge_desc	*cur_rx;
2391188808Sgonzo	struct mbuf		*m;
2392198667Sgonzo	int			rx_npkts = 0;
2393188808Sgonzo
2394188808Sgonzo	ARGE_LOCK_ASSERT(sc);
2395188808Sgonzo
2396188808Sgonzo	cons = sc->arge_cdata.arge_rx_cons;
2397188808Sgonzo
2398188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2399188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
2400188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2401188808Sgonzo
2402232627Sray	for (prog = 0; prog < ARGE_RX_RING_COUNT;
2403188808Sgonzo	    ARGE_INC(cons, ARGE_RX_RING_COUNT)) {
2404188808Sgonzo		cur_rx = &sc->arge_rdata.arge_rx_ring[cons];
2405188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[cons];
2406188808Sgonzo		m = rxd->rx_m;
2407188808Sgonzo
2408188808Sgonzo		if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0)
2409232627Sray		       break;
2410188808Sgonzo
2411188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
2412188808Sgonzo
2413188808Sgonzo		prog++;
2414188808Sgonzo
2415188808Sgonzo		packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl);
2416188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
2417195434Sgonzo		    BUS_DMASYNC_POSTREAD);
2418188808Sgonzo		m = rxd->rx_m;
2419188808Sgonzo
2420289671Sadrian		/*
2421289671Sadrian		 * If the MAC requires 4 byte alignment then the RX setup
2422289671Sadrian		 * routine will have pre-offset things; so un-offset it here.
2423289671Sadrian		 */
2424289671Sadrian		if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE)
2425289671Sadrian			arge_fixup_rx(m);
2426289671Sadrian
2427188808Sgonzo		m->m_pkthdr.rcvif = ifp;
2428188808Sgonzo		/* Skip 4 bytes of CRC */
2429188808Sgonzo		m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
2430271858Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
2431198667Sgonzo		rx_npkts++;
2432188808Sgonzo
2433188808Sgonzo		ARGE_UNLOCK(sc);
2434188808Sgonzo		(*ifp->if_input)(ifp, m);
2435188808Sgonzo		ARGE_LOCK(sc);
2436192783Sgonzo		cur_rx->packet_addr = 0;
2437192783Sgonzo	}
2438188808Sgonzo
2439192783Sgonzo	if (prog > 0) {
2440192783Sgonzo
2441192783Sgonzo		i = sc->arge_cdata.arge_rx_cons;
2442192783Sgonzo		for (; prog > 0 ; prog--) {
2443192783Sgonzo			if (arge_newbuf(sc, i) != 0) {
2444232627Sray				device_printf(sc->arge_dev,
2445192783Sgonzo				    "Failed to allocate buffer\n");
2446192783Sgonzo				break;
2447192783Sgonzo			}
2448192783Sgonzo			ARGE_INC(i, ARGE_RX_RING_COUNT);
2449188808Sgonzo		}
2450188808Sgonzo
2451188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2452188808Sgonzo		    sc->arge_cdata.arge_rx_ring_map,
2453195434Sgonzo		    BUS_DMASYNC_PREWRITE);
2454188808Sgonzo
2455188808Sgonzo		sc->arge_cdata.arge_rx_cons = cons;
2456188808Sgonzo	}
2457198667Sgonzo
2458198667Sgonzo	return (rx_npkts);
2459188808Sgonzo}
2460188808Sgonzo
2461188808Sgonzostatic int
2462188808Sgonzoarge_intr_filter(void *arg)
2463188808Sgonzo{
2464188808Sgonzo	struct arge_softc	*sc = arg;
2465188808Sgonzo	uint32_t		status, ints;
2466188808Sgonzo
2467188808Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
2468188808Sgonzo	ints = ARGE_READ(sc, AR71XX_DMA_INTR);
2469188808Sgonzo
2470220354Sadrian	ARGEDEBUG(sc, ARGE_DBG_INTR, "int mask(filter) = %b\n", ints,
2471188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
2472188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
2473232627Sray	ARGEDEBUG(sc, ARGE_DBG_INTR, "status(filter) = %b\n", status,
2474188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
2475188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
2476188808Sgonzo
2477188808Sgonzo	if (status & DMA_INTR_ALL) {
2478191644Sgonzo		sc->arge_intr_status |= status;
2479192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
2480289476Sadrian		sc->stats.intr_ok++;
2481188808Sgonzo		return (FILTER_SCHEDULE_THREAD);
2482232627Sray	}
2483188808Sgonzo
2484188808Sgonzo	sc->arge_intr_status = 0;
2485289476Sadrian	sc->stats.intr_stray++;
2486188808Sgonzo	return (FILTER_STRAY);
2487188808Sgonzo}
2488188808Sgonzo
2489188808Sgonzostatic void
2490188808Sgonzoarge_intr(void *arg)
2491188808Sgonzo{
2492188808Sgonzo	struct arge_softc	*sc = arg;
2493188808Sgonzo	uint32_t		status;
2494220356Sadrian	struct ifnet		*ifp = sc->arge_ifp;
2495290090Sadrian#ifdef	ARGE_DEBUG
2496290090Sadrian	int i;
2497290090Sadrian#endif
2498188808Sgonzo
2499192783Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
2500192783Sgonzo	status |= sc->arge_intr_status;
2501188808Sgonzo
2502232627Sray	ARGEDEBUG(sc, ARGE_DBG_INTR, "int status(intr) = %b\n", status,
2503188808Sgonzo	    "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD"
2504188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
2505188808Sgonzo
2506232627Sray	/*
2507232627Sray	 * Is it our interrupt at all?
2508188808Sgonzo	 */
2509289476Sadrian	if (status == 0) {
2510289476Sadrian		sc->stats.intr_stray2++;
2511188808Sgonzo		return;
2512289476Sadrian	}
2513188808Sgonzo
2514290090Sadrian#ifdef	ARGE_DEBUG
2515290090Sadrian	for (i = 0; i < 32; i++) {
2516290214Sadrian		if (status & (1U << i)) {
2517290123Sadrian			sc->intr_stats.count[i]++;
2518290090Sadrian		}
2519290090Sadrian	}
2520290090Sadrian#endif
2521290090Sadrian
2522188808Sgonzo	if (status & DMA_INTR_RX_BUS_ERROR) {
2523188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR);
2524188808Sgonzo		device_printf(sc->arge_dev, "RX bus error");
2525188808Sgonzo		return;
2526188808Sgonzo	}
2527188808Sgonzo
2528188808Sgonzo	if (status & DMA_INTR_TX_BUS_ERROR) {
2529188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR);
2530188808Sgonzo		device_printf(sc->arge_dev, "TX bus error");
2531188808Sgonzo		return;
2532188808Sgonzo	}
2533188808Sgonzo
2534192783Sgonzo	ARGE_LOCK(sc);
2535285121Sadrian	arge_flush_ddr(sc);
2536188808Sgonzo
2537192783Sgonzo	if (status & DMA_INTR_RX_PKT_RCVD)
2538192783Sgonzo		arge_rx_locked(sc);
2539188808Sgonzo
2540232627Sray	/*
2541232627Sray	 * RX overrun disables the receiver.
2542232627Sray	 * Clear indication and re-enable rx.
2543192783Sgonzo	 */
2544192783Sgonzo	if ( status & DMA_INTR_RX_OVERFLOW) {
2545192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW);
2546192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
2547220356Sadrian		sc->stats.rx_overflow++;
2548192783Sgonzo	}
2549188808Sgonzo
2550192783Sgonzo	if (status & DMA_INTR_TX_PKT_SENT)
2551192783Sgonzo		arge_tx_locked(sc);
2552232627Sray	/*
2553232627Sray	 * Underrun turns off TX. Clear underrun indication.
2554232627Sray	 * If there's anything left in the ring, reactivate the tx.
2555192783Sgonzo	 */
2556192569Sdwhite	if (status & DMA_INTR_TX_UNDERRUN) {
2557192569Sdwhite		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN);
2558220356Sadrian		sc->stats.tx_underflow++;
2559232628Sray		ARGEDEBUG(sc, ARGE_DBG_TX, "%s: TX underrun; tx_cnt=%d\n",
2560232628Sray		    __func__, sc->arge_cdata.arge_tx_cnt);
2561219590Sadrian		if (sc->arge_cdata.arge_tx_cnt > 0 ) {
2562232627Sray			ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL,
2563192783Sgonzo			    DMA_TX_CONTROL_EN);
2564192783Sgonzo		}
2565192569Sdwhite	}
2566192569Sdwhite
2567192946Sgonzo	/*
2568220357Sadrian	 * If we've finished TXing and there's space for more packets
2569220357Sadrian	 * to be queued for TX, do so. Otherwise we may end up in a
2570220357Sadrian	 * situation where the interface send queue was filled
2571220357Sadrian	 * whilst the hardware queue was full, then the hardware
2572220357Sadrian	 * queue was drained by the interface send queue wasn't,
2573220357Sadrian	 * and thus if_start() is never called to kick-start
2574220357Sadrian	 * the send process (and all subsequent packets are simply
2575220357Sadrian	 * discarded.
2576220357Sadrian	 *
2577220357Sadrian	 * XXX TODO: make sure that the hardware deals nicely
2578220357Sadrian	 * with the possibility of the queue being enabled above
2579220357Sadrian	 * after a TX underrun, then having the hardware queue added
2580220357Sadrian	 * to below.
2581220357Sadrian	 */
2582220357Sadrian	if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) &&
2583220357Sadrian	    (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
2584220357Sadrian		if (!IFQ_IS_EMPTY(&ifp->if_snd))
2585220357Sadrian			arge_start_locked(ifp);
2586220357Sadrian	}
2587220357Sadrian
2588220357Sadrian	/*
2589192946Sgonzo	 * We handled all bits, clear status
2590192946Sgonzo	 */
2591192946Sgonzo	sc->arge_intr_status = 0;
2592188808Sgonzo	ARGE_UNLOCK(sc);
2593192783Sgonzo	/*
2594232627Sray	 * re-enable all interrupts
2595192783Sgonzo	 */
2596192783Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
2597188808Sgonzo}
2598188808Sgonzo
2599192783Sgonzo
2600188808Sgonzostatic void
2601188808Sgonzoarge_tick(void *xsc)
2602188808Sgonzo{
2603188808Sgonzo	struct arge_softc	*sc = xsc;
2604188808Sgonzo	struct mii_data		*mii;
2605188808Sgonzo
2606188808Sgonzo	ARGE_LOCK_ASSERT(sc);
2607188808Sgonzo
2608199234Sgonzo	if (sc->arge_miibus) {
2609199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
2610199234Sgonzo		mii_tick(mii);
2611199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
2612199234Sgonzo	}
2613188808Sgonzo}
2614199234Sgonzo
2615199234Sgonzoint
2616199234Sgonzoarge_multiphy_mediachange(struct ifnet *ifp)
2617199234Sgonzo{
2618199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
2619199234Sgonzo	struct ifmedia *ifm = &sc->arge_ifmedia;
2620199234Sgonzo	struct ifmedia_entry *ife = ifm->ifm_cur;
2621199234Sgonzo
2622199234Sgonzo	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
2623199234Sgonzo		return (EINVAL);
2624199234Sgonzo
2625199234Sgonzo	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
2626232627Sray		device_printf(sc->arge_dev,
2627199234Sgonzo		    "AUTO is not supported for multiphy MAC");
2628199234Sgonzo		return (EINVAL);
2629199234Sgonzo	}
2630199234Sgonzo
2631199234Sgonzo	/*
2632199234Sgonzo	 * Ignore everything
2633199234Sgonzo	 */
2634199234Sgonzo	return (0);
2635199234Sgonzo}
2636199234Sgonzo
2637199234Sgonzovoid
2638199234Sgonzoarge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
2639199234Sgonzo{
2640199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
2641199234Sgonzo
2642199234Sgonzo	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
2643232627Sray	ifmr->ifm_active = IFM_ETHER | sc->arge_media_type |
2644199234Sgonzo	    sc->arge_duplex_mode;
2645199234Sgonzo}
2646199234Sgonzo
2647234862Sadrian#if defined(ARGE_MDIO)
2648234862Sadrianstatic int
2649234862Sadrianargemdio_probe(device_t dev)
2650234862Sadrian{
2651234862Sadrian	device_set_desc(dev, "Atheros AR71xx built-in ethernet interface, MDIO controller");
2652234862Sadrian	return (0);
2653234862Sadrian}
2654234862Sadrian
2655234862Sadrianstatic int
2656234862Sadrianargemdio_attach(device_t dev)
2657234862Sadrian{
2658234862Sadrian	struct arge_softc	*sc;
2659234862Sadrian	int			error = 0;
2660234862Sadrian
2661234862Sadrian	sc = device_get_softc(dev);
2662234862Sadrian	sc->arge_dev = dev;
2663234862Sadrian	sc->arge_mac_unit = device_get_unit(dev);
2664234862Sadrian	sc->arge_rid = 0;
2665234862Sadrian	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2666234862Sadrian	    &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE);
2667234862Sadrian	if (sc->arge_res == NULL) {
2668234862Sadrian		device_printf(dev, "couldn't map memory\n");
2669234862Sadrian		error = ENXIO;
2670234862Sadrian		goto fail;
2671234862Sadrian	}
2672234862Sadrian
2673234862Sadrian	/* Reset MAC - required for AR71xx MDIO to successfully occur */
2674234862Sadrian	arge_reset_mac(sc);
2675234862Sadrian	/* Reset MII bus */
2676234862Sadrian	arge_reset_miibus(sc);
2677234862Sadrian
2678234862Sadrian	bus_generic_probe(dev);
2679234862Sadrian	bus_enumerate_hinted_children(dev);
2680234862Sadrian	error = bus_generic_attach(dev);
2681234862Sadrianfail:
2682234862Sadrian	return (error);
2683234862Sadrian}
2684234862Sadrian
2685234862Sadrianstatic int
2686234862Sadrianargemdio_detach(device_t dev)
2687234862Sadrian{
2688234862Sadrian	return (0);
2689234862Sadrian}
2690234862Sadrian
2691234862Sadrian#endif
2692