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: stable/11/sys/mips/atheros/if_arge.c 323205 2017-09-06 02:07:44Z emaste $");
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 <sys/bus.h>
69188808Sgonzo#include <sys/rman.h>
70188808Sgonzo
71188808Sgonzo#include <dev/mii/mii.h>
72188808Sgonzo#include <dev/mii/miivar.h>
73188808Sgonzo
74188808Sgonzo#include <dev/pci/pcireg.h>
75188808Sgonzo#include <dev/pci/pcivar.h>
76188808Sgonzo
77234862Sadrian#include "opt_arge.h"
78234862Sadrian
79234862Sadrian#if defined(ARGE_MDIO)
80292766Sadrian#include <dev/mdio/mdio.h>
81234862Sadrian#include <dev/etherswitch/miiproxy.h>
82234862Sadrian#include "mdio_if.h"
83234862Sadrian#endif
84234862Sadrian
85234862Sadrian
86188808SgonzoMODULE_DEPEND(arge, ether, 1, 1, 1);
87188808SgonzoMODULE_DEPEND(arge, miibus, 1, 1, 1);
88234862SadrianMODULE_VERSION(arge, 1);
89188808Sgonzo
90188808Sgonzo#include "miibus_if.h"
91188808Sgonzo
92280798Sadrian#include <net/ethernet.h>
93280798Sadrian
94188808Sgonzo#include <mips/atheros/ar71xxreg.h>
95256575Sadrian#include <mips/atheros/ar934xreg.h>	/* XXX tsk! */
96290910Sadrian#include <mips/atheros/qca953xreg.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	}
402290910Sadrian
403290910Sadrian	if (ar71xx_soc == AR71XX_SOC_QCA9533 ||
404290910Sadrian	   ar71xx_soc == AR71XX_SOC_QCA9533_V2) {
405290910Sadrian		if (sc->arge_mac_unit == 0) {
406290910Sadrian			reset_reg |= QCA953X_RESET_GE0_MDIO;
407290910Sadrian		} else {
408290910Sadrian			reset_reg |= QCA953X_RESET_GE1_MDIO;
409290910Sadrian		}
410290910Sadrian	}
411290910Sadrian
412256575Sadrian	ar71xx_device_stop(reset_reg);
413234862Sadrian	DELAY(100);
414256575Sadrian	ar71xx_device_start(reset_reg);
415234862Sadrian
416234862Sadrian	/* Step 3. Reconfigure MAC block */
417234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_CFG1,
418234862Sadrian		MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE |
419234862Sadrian		MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE);
420234862Sadrian
421234862Sadrian	reg = ARGE_READ(sc, AR71XX_MAC_CFG2);
422234862Sadrian	reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ;
423234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg);
424234862Sadrian
425234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536);
426234862Sadrian}
427234862Sadrian
428256575Sadrian/*
429256648Sadrian * These values map to the divisor values programmed into
430256648Sadrian * AR71XX_MAC_MII_CFG.
431256648Sadrian *
432256648Sadrian * The index of each value corresponds to the divisor section
433256648Sadrian * value in AR71XX_MAC_MII_CFG (ie, table[0] means '0' in
434256648Sadrian * AR71XX_MAC_MII_CFG, table[1] means '1', etc.)
435256648Sadrian */
436256648Sadrianstatic const uint32_t ar71xx_mdio_div_table[] = {
437256648Sadrian	4, 4, 6, 8, 10, 14, 20, 28,
438256648Sadrian};
439256648Sadrian
440256648Sadrianstatic const uint32_t ar7240_mdio_div_table[] = {
441256648Sadrian	2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
442256648Sadrian};
443256648Sadrian
444256648Sadrianstatic const uint32_t ar933x_mdio_div_table[] = {
445256648Sadrian	4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
446256648Sadrian};
447256648Sadrian
448256648Sadrian/*
449256648Sadrian * Lookup the divisor to use based on the given frequency.
450256648Sadrian *
451256648Sadrian * Returns the divisor to use, or -ve on error.
452256648Sadrian */
453256648Sadrianstatic int
454256648Sadrianarge_mdio_get_divider(struct arge_softc *sc, unsigned long mdio_clock)
455256648Sadrian{
456256648Sadrian	unsigned long ref_clock, t;
457256648Sadrian	const uint32_t *table;
458256648Sadrian	int ndivs;
459256648Sadrian	int i;
460256648Sadrian
461256648Sadrian	/*
462256648Sadrian	 * This is the base MDIO frequency on the SoC.
463256648Sadrian	 * The dividers .. well, divide. Duh.
464256648Sadrian	 */
465256648Sadrian	ref_clock = ar71xx_mdio_freq();
466256648Sadrian
467256648Sadrian	/*
468256648Sadrian	 * If either clock is undefined, just tell the
469256648Sadrian	 * caller to fall through to the defaults.
470256648Sadrian	 */
471256648Sadrian	if (ref_clock == 0 || mdio_clock == 0)
472256648Sadrian		return (-EINVAL);
473256648Sadrian
474256648Sadrian	/*
475256648Sadrian	 * Pick the correct table!
476256648Sadrian	 */
477256648Sadrian	switch (ar71xx_soc) {
478256648Sadrian	case AR71XX_SOC_AR9330:
479256648Sadrian	case AR71XX_SOC_AR9331:
480256648Sadrian	case AR71XX_SOC_AR9341:
481256648Sadrian	case AR71XX_SOC_AR9342:
482256648Sadrian	case AR71XX_SOC_AR9344:
483290910Sadrian	case AR71XX_SOC_QCA9533:
484290910Sadrian	case AR71XX_SOC_QCA9533_V2:
485279510Sadrian	case AR71XX_SOC_QCA9556:
486279510Sadrian	case AR71XX_SOC_QCA9558:
487256648Sadrian		table = ar933x_mdio_div_table;
488256648Sadrian		ndivs = nitems(ar933x_mdio_div_table);
489256648Sadrian		break;
490256648Sadrian
491256648Sadrian	case AR71XX_SOC_AR7240:
492256648Sadrian	case AR71XX_SOC_AR7241:
493256648Sadrian	case AR71XX_SOC_AR7242:
494256648Sadrian		table = ar7240_mdio_div_table;
495256648Sadrian		ndivs = nitems(ar7240_mdio_div_table);
496256648Sadrian		break;
497256648Sadrian
498256648Sadrian	default:
499256648Sadrian		table = ar71xx_mdio_div_table;
500256648Sadrian		ndivs = nitems(ar71xx_mdio_div_table);
501256648Sadrian	}
502256648Sadrian
503256648Sadrian	/*
504256648Sadrian	 * Now, walk through the list and find the first divisor
505256648Sadrian	 * that falls under the target MDIO frequency.
506256648Sadrian	 *
507256648Sadrian	 * The divisors go up, but the corresponding frequencies
508256648Sadrian	 * are actually decreasing.
509256648Sadrian	 */
510256648Sadrian	for (i = 0; i < ndivs; i++) {
511256648Sadrian		t = ref_clock / table[i];
512256648Sadrian		if (t <= mdio_clock) {
513256648Sadrian			return (i);
514256648Sadrian		}
515256648Sadrian	}
516256648Sadrian
517256648Sadrian	ARGEDEBUG(sc, ARGE_DBG_RESET,
518256648Sadrian	    "No divider found; MDIO=%lu Hz; target=%lu Hz\n",
519256648Sadrian		ref_clock, mdio_clock);
520256648Sadrian	return (-ENOENT);
521256648Sadrian}
522256648Sadrian
523256648Sadrian/*
524256575Sadrian * Fetch the MDIO bus clock rate.
525256575Sadrian *
526256575Sadrian * For now, the default is DIV_28 for everything
527256648Sadrian * bar AR934x, which will be DIV_58.
528256575Sadrian *
529256575Sadrian * It will definitely need updating to take into account
530256575Sadrian * the MDIO bus core clock rate and the target clock
531256575Sadrian * rate for the chip.
532256575Sadrian */
533256575Sadrianstatic uint32_t
534256575Sadrianarge_fetch_mdiobus_clock_rate(struct arge_softc *sc)
535256575Sadrian{
536256648Sadrian	int mdio_freq, div;
537256575Sadrian
538256648Sadrian	/*
539256648Sadrian	 * Is the MDIO frequency defined? If so, find a divisor that
540256648Sadrian	 * makes reasonable sense.  Don't overshoot the frequency.
541256648Sadrian	 */
542256648Sadrian	if (resource_int_value(device_get_name(sc->arge_dev),
543256648Sadrian	    device_get_unit(sc->arge_dev),
544256648Sadrian	    "mdio_freq",
545256648Sadrian	    &mdio_freq) == 0) {
546256648Sadrian		sc->arge_mdiofreq = mdio_freq;
547256648Sadrian		div = arge_mdio_get_divider(sc, sc->arge_mdiofreq);
548256648Sadrian		if (bootverbose)
549256648Sadrian			device_printf(sc->arge_dev,
550256648Sadrian			    "%s: mdio ref freq=%llu Hz, target freq=%llu Hz,"
551256648Sadrian			    " divisor index=%d\n",
552256648Sadrian			    __func__,
553256648Sadrian			    (unsigned long long) ar71xx_mdio_freq(),
554256648Sadrian			    (unsigned long long) mdio_freq,
555256648Sadrian			    div);
556256648Sadrian		if (div >= 0)
557256648Sadrian			return (div);
558256648Sadrian	}
559256648Sadrian
560256648Sadrian	/*
561256648Sadrian	 * Default value(s).
562256648Sadrian	 *
563256648Sadrian	 * XXX obviously these need .. fixing.
564256648Sadrian	 *
565256648Sadrian	 * From Linux/OpenWRT:
566256648Sadrian	 *
567256648Sadrian	 * + 7240? DIV_6
568256648Sadrian	 * + Builtin-switch port and not 934x? DIV_10
569256648Sadrian	 * + Not built-in switch port and 934x? DIV_58
570256648Sadrian	 * + .. else DIV_28.
571256648Sadrian	 */
572256575Sadrian	switch (ar71xx_soc) {
573256575Sadrian	case AR71XX_SOC_AR9341:
574256575Sadrian	case AR71XX_SOC_AR9342:
575256575Sadrian	case AR71XX_SOC_AR9344:
576290910Sadrian	case AR71XX_SOC_QCA9533:
577290910Sadrian	case AR71XX_SOC_QCA9533_V2:
578279510Sadrian	case AR71XX_SOC_QCA9556:
579279510Sadrian	case AR71XX_SOC_QCA9558:
580256648Sadrian		return (MAC_MII_CFG_CLOCK_DIV_58);
581256648Sadrian		break;
582256575Sadrian	default:
583256575Sadrian		return (MAC_MII_CFG_CLOCK_DIV_28);
584256575Sadrian	}
585256575Sadrian}
586256575Sadrian
587234862Sadrianstatic void
588234862Sadrianarge_reset_miibus(struct arge_softc *sc)
589234862Sadrian{
590256575Sadrian	uint32_t mdio_div;
591234862Sadrian
592256575Sadrian	mdio_div = arge_fetch_mdiobus_clock_rate(sc);
593256575Sadrian
594256575Sadrian	/*
595256575Sadrian	 * XXX AR934x and later; should we be also resetting the
596256575Sadrian	 * MDIO block(s) using the reset register block?
597256575Sadrian	 */
598256575Sadrian
599256575Sadrian	/* Reset MII bus; program in the default divisor */
600256575Sadrian	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET | mdio_div);
601234862Sadrian	DELAY(100);
602256575Sadrian	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, mdio_div);
603234862Sadrian	DELAY(100);
604234862Sadrian}
605234862Sadrian
606234919Sadrianstatic void
607234919Sadrianarge_fetch_pll_config(struct arge_softc *sc)
608234919Sadrian{
609234919Sadrian	long int val;
610234919Sadrian
611234919Sadrian	if (resource_long_value(device_get_name(sc->arge_dev),
612234919Sadrian	    device_get_unit(sc->arge_dev),
613234919Sadrian	    "pll_10", &val) == 0) {
614234919Sadrian		sc->arge_pllcfg.pll_10 = val;
615234919Sadrian		device_printf(sc->arge_dev, "%s: pll_10 = 0x%x\n",
616234919Sadrian		    __func__, (int) val);
617234919Sadrian	}
618234919Sadrian	if (resource_long_value(device_get_name(sc->arge_dev),
619234919Sadrian	    device_get_unit(sc->arge_dev),
620234919Sadrian	    "pll_100", &val) == 0) {
621234919Sadrian		sc->arge_pllcfg.pll_100 = val;
622234919Sadrian		device_printf(sc->arge_dev, "%s: pll_100 = 0x%x\n",
623234919Sadrian		    __func__, (int) val);
624234919Sadrian	}
625234919Sadrian	if (resource_long_value(device_get_name(sc->arge_dev),
626234919Sadrian	    device_get_unit(sc->arge_dev),
627234919Sadrian	    "pll_1000", &val) == 0) {
628234919Sadrian		sc->arge_pllcfg.pll_1000 = val;
629234919Sadrian		device_printf(sc->arge_dev, "%s: pll_1000 = 0x%x\n",
630234919Sadrian		    __func__, (int) val);
631234919Sadrian	}
632234919Sadrian}
633234919Sadrian
634188808Sgonzostatic int
635188808Sgonzoarge_attach(device_t dev)
636188808Sgonzo{
637188808Sgonzo	struct ifnet		*ifp;
638188808Sgonzo	struct arge_softc	*sc;
639280798Sadrian	int			error = 0, rid, i;
640199234Sgonzo	uint32_t		hint;
641220260Sadrian	long			eeprom_mac_addr = 0;
642234910Sadrian	int			miicfg = 0;
643254690Ssbruno	int			readascii = 0;
644263224Sadrian	int			local_mac = 0;
645280798Sadrian	uint8_t			local_macaddr[ETHER_ADDR_LEN];
646280798Sadrian	char *			local_macstr;
647280798Sadrian	char			devid_str[32];
648280798Sadrian	int			count;
649188808Sgonzo
650188808Sgonzo	sc = device_get_softc(dev);
651188808Sgonzo	sc->arge_dev = dev;
652188808Sgonzo	sc->arge_mac_unit = device_get_unit(dev);
653188808Sgonzo
654220260Sadrian	/*
655280798Sadrian	 * See if there's a "board" MAC address hint available for
656280798Sadrian	 * this particular device.
657280798Sadrian	 *
658280798Sadrian	 * This is in the environment - it'd be nice to use the resource_*()
659280798Sadrian	 * routines, but at the moment the system is booting, the resource hints
660280798Sadrian	 * are set to the 'static' map so they're not pulling from kenv.
661280798Sadrian	 */
662280798Sadrian	snprintf(devid_str, 32, "hint.%s.%d.macaddr",
663280798Sadrian	    device_get_name(dev),
664280798Sadrian	    device_get_unit(dev));
665280798Sadrian	if ((local_macstr = kern_getenv(devid_str)) != NULL) {
666280798Sadrian		uint32_t tmpmac[ETHER_ADDR_LEN];
667280798Sadrian
668280798Sadrian		/* Have a MAC address; should use it */
669280798Sadrian		device_printf(dev, "Overriding MAC address from environment: '%s'\n",
670280798Sadrian		    local_macstr);
671280798Sadrian
672280798Sadrian		/* Extract out the MAC address */
673280798Sadrian		/* XXX this should all be a generic method */
674280798Sadrian		count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x",
675280798Sadrian		    &tmpmac[0], &tmpmac[1],
676280798Sadrian		    &tmpmac[2], &tmpmac[3],
677280798Sadrian		    &tmpmac[4], &tmpmac[5]);
678280798Sadrian		if (count == 6) {
679280798Sadrian			/* Valid! */
680280798Sadrian			local_mac = 1;
681280798Sadrian			for (i = 0; i < ETHER_ADDR_LEN; i++)
682280798Sadrian				local_macaddr[i] = tmpmac[i];
683280798Sadrian		}
684280798Sadrian		/* Done! */
685280798Sadrian		freeenv(local_macstr);
686280798Sadrian		local_macstr = NULL;
687280798Sadrian	}
688280798Sadrian
689280798Sadrian	/*
690289476Sadrian	 * Hardware workarounds.
691289476Sadrian	 */
692289476Sadrian	switch (ar71xx_soc) {
693289744Sadrian	case AR71XX_SOC_AR9330:
694289744Sadrian	case AR71XX_SOC_AR9331:
695289898Sadrian	case AR71XX_SOC_AR9341:
696289898Sadrian	case AR71XX_SOC_AR9342:
697289898Sadrian	case AR71XX_SOC_AR9344:
698290910Sadrian	case AR71XX_SOC_QCA9533:
699290910Sadrian	case AR71XX_SOC_QCA9533_V2:
700289476Sadrian	case AR71XX_SOC_QCA9556:
701289476Sadrian	case AR71XX_SOC_QCA9558:
702289476Sadrian		/* Arbitrary alignment */
703289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE;
704289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE;
705289476Sadrian		break;
706289476Sadrian	default:
707289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE;
708289476Sadrian		sc->arge_hw_flags |= ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE;
709289476Sadrian		break;
710289476Sadrian	}
711289476Sadrian
712289476Sadrian	/*
713220260Sadrian	 * Some units (eg the TP-Link WR-1043ND) do not have a convenient
714220260Sadrian	 * EEPROM location to read the ethernet MAC address from.
715220260Sadrian	 * OpenWRT simply snaffles it from a fixed location.
716220260Sadrian	 *
717220260Sadrian	 * Since multiple units seem to use this feature, include
718220260Sadrian	 * a method of setting the MAC address based on an flash location
719220260Sadrian	 * in CPU address space.
720254690Ssbruno	 *
721254690Ssbruno	 * Some vendors have decided to store the mac address as a literal
722254690Ssbruno	 * string of 18 characters in xx:xx:xx:xx:xx:xx format instead of
723254690Ssbruno	 * an array of numbers.  Expose a hint to turn on this conversion
724254690Ssbruno	 * feature via strtol()
725220260Sadrian	 */
726280798Sadrian	 if (local_mac == 0 && resource_long_value(device_get_name(dev),
727280798Sadrian	     device_get_unit(dev), "eeprommac", &eeprom_mac_addr) == 0) {
728263224Sadrian		local_mac = 1;
729220260Sadrian		int i;
730232628Sray		const char *mac =
731232628Sray		    (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr);
732220260Sadrian		device_printf(dev, "Overriding MAC from EEPROM\n");
733254690Ssbruno		if (resource_int_value(device_get_name(dev), device_get_unit(dev),
734254690Ssbruno			"readascii", &readascii) == 0) {
735254690Ssbruno			device_printf(dev, "Vendor stores MAC in ASCII format\n");
736254690Ssbruno			for (i = 0; i < 6; i++) {
737280798Sadrian				local_macaddr[i] = strtol(&(mac[i*3]), NULL, 16);
738254690Ssbruno			}
739254690Ssbruno		} else {
740254690Ssbruno			for (i = 0; i < 6; i++) {
741280798Sadrian				local_macaddr[i] = mac[i];
742254690Ssbruno			}
743220260Sadrian		}
744220260Sadrian	}
745220260Sadrian
746232627Sray	KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)),
747188808Sgonzo	    ("if_arge: Only MAC0 and MAC1 supported"));
748188808Sgonzo
749188808Sgonzo	/*
750234919Sadrian	 * Fetch the PLL configuration.
751234919Sadrian	 */
752234919Sadrian	arge_fetch_pll_config(sc);
753234919Sadrian
754234919Sadrian	/*
755234910Sadrian	 * Get the MII configuration, if applicable.
756234910Sadrian	 */
757234910Sadrian	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
758234910Sadrian	    "miimode", &miicfg) == 0) {
759234910Sadrian		/* XXX bounds check? */
760234910Sadrian		device_printf(dev, "%s: overriding MII mode to '%s'\n",
761234910Sadrian		    __func__, arge_miicfg_str[miicfg]);
762234910Sadrian		sc->arge_miicfg = miicfg;
763234910Sadrian	}
764234910Sadrian
765234910Sadrian	/*
766188808Sgonzo	 *  Get which PHY of 5 available we should use for this unit
767188808Sgonzo	 */
768234862Sadrian	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
769234862Sadrian	    "phymask", &sc->arge_phymask) != 0) {
770188808Sgonzo		/*
771232627Sray		 * Use port 4 (WAN) for GE0. For any other port use
772232627Sray		 * its PHY the same as its unit number
773188808Sgonzo		 */
774188808Sgonzo		if (sc->arge_mac_unit == 0)
775234862Sadrian			sc->arge_phymask = (1 << 4);
776188808Sgonzo		else
777199234Sgonzo			/* Use all phys up to 4 */
778234862Sadrian			sc->arge_phymask = (1 << 4) - 1;
779188808Sgonzo
780234862Sadrian		device_printf(dev, "No PHY specified, using mask %d\n", sc->arge_phymask);
781188808Sgonzo	}
782188808Sgonzo
783199234Sgonzo	/*
784279791Sadrian	 * Get default/hard-coded media & duplex mode.
785199234Sgonzo	 */
786232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
787199234Sgonzo	    "media", &hint) != 0)
788199234Sgonzo		hint = 0;
789188808Sgonzo
790199234Sgonzo	if (hint == 1000)
791199234Sgonzo		sc->arge_media_type = IFM_1000_T;
792279791Sadrian	else if (hint == 100)
793279791Sadrian		sc->arge_media_type = IFM_100_TX;
794279791Sadrian	else if (hint == 10)
795279791Sadrian		sc->arge_media_type = IFM_10_T;
796199234Sgonzo	else
797279791Sadrian		sc->arge_media_type = 0;
798199234Sgonzo
799232627Sray	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
800199234Sgonzo	    "fduplex", &hint) != 0)
801199234Sgonzo		hint = 1;
802199234Sgonzo
803199234Sgonzo	if (hint)
804199234Sgonzo		sc->arge_duplex_mode = IFM_FDX;
805199234Sgonzo	else
806199234Sgonzo		sc->arge_duplex_mode = 0;
807199234Sgonzo
808188808Sgonzo	mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
809188808Sgonzo	    MTX_DEF);
810188808Sgonzo	callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0);
811188808Sgonzo	TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc);
812188808Sgonzo
813188808Sgonzo	/* Map control/status registers. */
814188808Sgonzo	sc->arge_rid = 0;
815234862Sadrian	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
816234862Sadrian	    &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE);
817188808Sgonzo
818188808Sgonzo	if (sc->arge_res == NULL) {
819188808Sgonzo		device_printf(dev, "couldn't map memory\n");
820188808Sgonzo		error = ENXIO;
821188808Sgonzo		goto fail;
822188808Sgonzo	}
823188808Sgonzo
824188808Sgonzo	/* Allocate interrupts */
825188808Sgonzo	rid = 0;
826232627Sray	sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
827188808Sgonzo	    RF_SHAREABLE | RF_ACTIVE);
828188808Sgonzo
829188808Sgonzo	if (sc->arge_irq == NULL) {
830188808Sgonzo		device_printf(dev, "couldn't map interrupt\n");
831188808Sgonzo		error = ENXIO;
832188808Sgonzo		goto fail;
833188808Sgonzo	}
834188808Sgonzo
835188808Sgonzo	/* Allocate ifnet structure. */
836188808Sgonzo	ifp = sc->arge_ifp = if_alloc(IFT_ETHER);
837188808Sgonzo
838188808Sgonzo	if (ifp == NULL) {
839188808Sgonzo		device_printf(dev, "couldn't allocate ifnet structure\n");
840188808Sgonzo		error = ENOSPC;
841188808Sgonzo		goto fail;
842188808Sgonzo	}
843188808Sgonzo
844188808Sgonzo	ifp->if_softc = sc;
845188808Sgonzo	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
846188808Sgonzo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
847188808Sgonzo	ifp->if_ioctl = arge_ioctl;
848188808Sgonzo	ifp->if_start = arge_start;
849188808Sgonzo	ifp->if_init = arge_init;
850198932Sgonzo	sc->arge_if_flags = ifp->if_flags;
851188808Sgonzo
852188808Sgonzo	/* XXX: add real size */
853207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
854207554Ssobomax	ifp->if_snd.ifq_maxlen = ifqmaxlen;
855188808Sgonzo	IFQ_SET_READY(&ifp->if_snd);
856188808Sgonzo
857268235Sloos	/* Tell the upper layer(s) we support long frames. */
858268235Sloos	ifp->if_capabilities |= IFCAP_VLAN_MTU;
859268235Sloos
860188808Sgonzo	ifp->if_capenable = ifp->if_capabilities;
861192783Sgonzo#ifdef DEVICE_POLLING
862192783Sgonzo	ifp->if_capabilities |= IFCAP_POLLING;
863192783Sgonzo#endif
864188808Sgonzo
865280798Sadrian	/* If there's a local mac defined, copy that in */
866280798Sadrian	if (local_mac == 1) {
867280798Sadrian		(void) ar71xx_mac_addr_init(sc->arge_eaddr,
868280798Sadrian		    local_macaddr, 0, 0);
869280798Sadrian	} else {
870192179Sgonzo		/*
871192179Sgonzo		 * No MAC address configured. Generate the random one.
872192179Sgonzo		 */
873198933Sgonzo		if  (bootverbose)
874232627Sray			device_printf(dev,
875192179Sgonzo			    "Generating random ethernet address.\n");
876280124Sadrian		(void) ar71xx_mac_addr_random_init(sc->arge_eaddr);
877192179Sgonzo	}
878263224Sadrian
879188808Sgonzo	if (arge_dma_alloc(sc) != 0) {
880188808Sgonzo		error = ENXIO;
881188808Sgonzo		goto fail;
882188808Sgonzo	}
883188808Sgonzo
884234862Sadrian	/*
885234862Sadrian	 * Don't do this for the MDIO bus case - it's already done
886234862Sadrian	 * as part of the MDIO bus attachment.
887292245Sadrian	 *
888292245Sadrian	 * XXX TODO: if we don't do this, we don't ever release the MAC
889292245Sadrian	 * from reset and we can't use the port.  Now, if we define ARGE_MDIO
890292245Sadrian	 * but we /don't/ define two MDIO busses, then we can't actually
891292245Sadrian	 * use both MACs.
892234862Sadrian	 */
893234862Sadrian#if !defined(ARGE_MDIO)
894192569Sdwhite	/* Initialize the MAC block */
895234862Sadrian	arge_reset_mac(sc);
896234862Sadrian	arge_reset_miibus(sc);
897234862Sadrian#endif
898232627Sray
899234910Sadrian	/* Configure MII mode, just for convienence */
900234910Sadrian	if (sc->arge_miicfg != 0)
901234910Sadrian		ar71xx_device_set_mii_if(sc->arge_mac_unit, sc->arge_miicfg);
902234910Sadrian
903232627Sray	/*
904188808Sgonzo	 * Set all Ethernet address registers to the same initial values
905232627Sray	 * set all four addresses to 66-88-aa-cc-dd-ee
906188808Sgonzo	 */
907234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, (sc->arge_eaddr[2] << 24)
908234862Sadrian	    | (sc->arge_eaddr[3] << 16) | (sc->arge_eaddr[4] << 8)
909234862Sadrian	    | sc->arge_eaddr[5]);
910234862Sadrian	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (sc->arge_eaddr[0] << 8)
911234862Sadrian	    | sc->arge_eaddr[1]);
912188808Sgonzo
913232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0,
914188808Sgonzo	    FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT);
915188808Sgonzo
916289476Sadrian	/*
917289476Sadrian	 * SoC specific bits.
918289476Sadrian	 */
919219589Sadrian	switch (ar71xx_soc) {
920219589Sadrian		case AR71XX_SOC_AR7240:
921219589Sadrian		case AR71XX_SOC_AR7241:
922219589Sadrian		case AR71XX_SOC_AR7242:
923249123Sadrian		case AR71XX_SOC_AR9330:
924249123Sadrian		case AR71XX_SOC_AR9331:
925256575Sadrian		case AR71XX_SOC_AR9341:
926256575Sadrian		case AR71XX_SOC_AR9342:
927256575Sadrian		case AR71XX_SOC_AR9344:
928290910Sadrian		case AR71XX_SOC_QCA9533:
929290910Sadrian		case AR71XX_SOC_QCA9533_V2:
930279510Sadrian		case AR71XX_SOC_QCA9556:
931279510Sadrian		case AR71XX_SOC_QCA9558:
932219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0010ffff);
933219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x015500aa);
934219589Sadrian			break;
935256575Sadrian		/* AR71xx, AR913x */
936219589Sadrian		default:
937219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000);
938219589Sadrian			ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff);
939219589Sadrian	}
940219589Sadrian
941232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH,
942192783Sgonzo	    FIFO_RX_FILTMATCH_DEFAULT);
943188808Sgonzo
944232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
945192783Sgonzo	    FIFO_RX_FILTMASK_DEFAULT);
946188808Sgonzo
947234862Sadrian#if defined(ARGE_MDIO)
948234862Sadrian	sc->arge_miiproxy = mii_attach_proxy(sc->arge_dev);
949234862Sadrian#endif
950199234Sgonzo
951234862Sadrian	device_printf(sc->arge_dev, "finishing attachment, phymask %04x"
952234862Sadrian	    ", proxy %s \n", sc->arge_phymask, sc->arge_miiproxy == NULL ?
953234862Sadrian	    "null" : "set");
954234862Sadrian	for (i = 0; i < ARGE_NPHY; i++) {
955234862Sadrian		if (((1 << i) & sc->arge_phymask) != 0) {
956234862Sadrian			error = mii_attach(sc->arge_miiproxy != NULL ?
957234862Sadrian			    sc->arge_miiproxy : sc->arge_dev,
958234862Sadrian			    &sc->arge_miibus, sc->arge_ifp,
959234862Sadrian			    arge_ifmedia_upd, arge_ifmedia_sts,
960234862Sadrian			    BMSR_DEFCAPMASK, i, MII_OFFSET_ANY, 0);
961234862Sadrian			if (error != 0) {
962234862Sadrian				device_printf(sc->arge_dev, "unable to attach"
963234862Sadrian				    " PHY %d: %d\n", i, error);
964234862Sadrian				goto fail;
965234862Sadrian			}
966199234Sgonzo		}
967199234Sgonzo	}
968279791Sadrian
969234862Sadrian	if (sc->arge_miibus == NULL) {
970234862Sadrian		/* no PHY, so use hard-coded values */
971279791Sadrian		ifmedia_init(&sc->arge_ifmedia, 0,
972199234Sgonzo		    arge_multiphy_mediachange,
973199234Sgonzo		    arge_multiphy_mediastatus);
974199234Sgonzo		ifmedia_add(&sc->arge_ifmedia,
975232627Sray		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode,
976199234Sgonzo		    0, NULL);
977199234Sgonzo		ifmedia_set(&sc->arge_ifmedia,
978199234Sgonzo		    IFM_ETHER | sc->arge_media_type  | sc->arge_duplex_mode);
979199234Sgonzo		arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode);
980199234Sgonzo	}
981199234Sgonzo
982188808Sgonzo	/* Call MI attach routine. */
983234862Sadrian	ether_ifattach(sc->arge_ifp, sc->arge_eaddr);
984188808Sgonzo
985188808Sgonzo	/* Hook interrupt last to avoid having to lock softc */
986234862Sadrian	error = bus_setup_intr(sc->arge_dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
987188808Sgonzo	    arge_intr_filter, arge_intr, sc, &sc->arge_intrhand);
988188808Sgonzo
989188808Sgonzo	if (error) {
990234862Sadrian		device_printf(sc->arge_dev, "couldn't set up irq\n");
991234862Sadrian		ether_ifdetach(sc->arge_ifp);
992188808Sgonzo		goto fail;
993188808Sgonzo	}
994188808Sgonzo
995209802Sadrian	/* setup sysctl variables */
996234862Sadrian	arge_attach_sysctl(sc->arge_dev);
997209802Sadrian
998188808Sgonzofail:
999234862Sadrian	if (error)
1000188808Sgonzo		arge_detach(dev);
1001188808Sgonzo
1002188808Sgonzo	return (error);
1003188808Sgonzo}
1004188808Sgonzo
1005188808Sgonzostatic int
1006188808Sgonzoarge_detach(device_t dev)
1007188808Sgonzo{
1008192783Sgonzo	struct arge_softc	*sc = device_get_softc(dev);
1009188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
1010188808Sgonzo
1011232628Sray	KASSERT(mtx_initialized(&sc->arge_mtx),
1012232628Sray	    ("arge mutex not initialized"));
1013188808Sgonzo
1014188808Sgonzo	/* These should only be active if attach succeeded */
1015188808Sgonzo	if (device_is_attached(dev)) {
1016188808Sgonzo		ARGE_LOCK(sc);
1017188808Sgonzo		sc->arge_detach = 1;
1018192783Sgonzo#ifdef DEVICE_POLLING
1019192783Sgonzo		if (ifp->if_capenable & IFCAP_POLLING)
1020192783Sgonzo			ether_poll_deregister(ifp);
1021192783Sgonzo#endif
1022192783Sgonzo
1023188808Sgonzo		arge_stop(sc);
1024188808Sgonzo		ARGE_UNLOCK(sc);
1025188808Sgonzo		taskqueue_drain(taskqueue_swi, &sc->arge_link_task);
1026188808Sgonzo		ether_ifdetach(ifp);
1027188808Sgonzo	}
1028188808Sgonzo
1029188808Sgonzo	if (sc->arge_miibus)
1030188808Sgonzo		device_delete_child(dev, sc->arge_miibus);
1031199234Sgonzo
1032234862Sadrian	if (sc->arge_miiproxy)
1033234862Sadrian		device_delete_child(dev, sc->arge_miiproxy);
1034234862Sadrian
1035188808Sgonzo	bus_generic_detach(dev);
1036188808Sgonzo
1037188808Sgonzo	if (sc->arge_intrhand)
1038188808Sgonzo		bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand);
1039188808Sgonzo
1040188808Sgonzo	if (sc->arge_res)
1041232627Sray		bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid,
1042188808Sgonzo		    sc->arge_res);
1043188808Sgonzo
1044188808Sgonzo	if (ifp)
1045188808Sgonzo		if_free(ifp);
1046188808Sgonzo
1047188808Sgonzo	arge_dma_free(sc);
1048188808Sgonzo
1049188808Sgonzo	mtx_destroy(&sc->arge_mtx);
1050188808Sgonzo
1051188808Sgonzo	return (0);
1052188808Sgonzo
1053188808Sgonzo}
1054188808Sgonzo
1055188808Sgonzostatic int
1056188808Sgonzoarge_suspend(device_t dev)
1057188808Sgonzo{
1058188808Sgonzo
1059188808Sgonzo	panic("%s", __func__);
1060188808Sgonzo	return 0;
1061188808Sgonzo}
1062188808Sgonzo
1063188808Sgonzostatic int
1064188808Sgonzoarge_resume(device_t dev)
1065188808Sgonzo{
1066188808Sgonzo
1067188808Sgonzo	panic("%s", __func__);
1068188808Sgonzo	return 0;
1069188808Sgonzo}
1070188808Sgonzo
1071194059Sgonzostatic int
1072188808Sgonzoarge_shutdown(device_t dev)
1073188808Sgonzo{
1074188808Sgonzo	struct arge_softc	*sc;
1075188808Sgonzo
1076188808Sgonzo	sc = device_get_softc(dev);
1077188808Sgonzo
1078188808Sgonzo	ARGE_LOCK(sc);
1079188808Sgonzo	arge_stop(sc);
1080188808Sgonzo	ARGE_UNLOCK(sc);
1081194059Sgonzo
1082194059Sgonzo	return (0);
1083188808Sgonzo}
1084188808Sgonzo
1085234862Sadrianstatic void
1086234862Sadrianarge_hinted_child(device_t bus, const char *dname, int dunit)
1087234862Sadrian{
1088234862Sadrian	BUS_ADD_CHILD(bus, 0, dname, dunit);
1089234862Sadrian	device_printf(bus, "hinted child %s%d\n", dname, dunit);
1090234862Sadrian}
1091234862Sadrian
1092188808Sgonzostatic int
1093290217Sadrianarge_mdio_busy(struct arge_softc *sc)
1094290217Sadrian{
1095290217Sadrian	int i,result;
1096290217Sadrian
1097290217Sadrian	for (i = 0; i < ARGE_MII_TIMEOUT; i++) {
1098290217Sadrian		DELAY(5);
1099290217Sadrian		ARGE_MDIO_BARRIER_READ(sc);
1100290217Sadrian		result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR);
1101290217Sadrian		if (! result)
1102290217Sadrian			return (0);
1103290217Sadrian		DELAY(5);
1104290217Sadrian	}
1105290217Sadrian	return (-1);
1106290217Sadrian}
1107290217Sadrian
1108290217Sadrianstatic int
1109188808Sgonzoarge_miibus_readreg(device_t dev, int phy, int reg)
1110188808Sgonzo{
1111188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
1112290217Sadrian	int result;
1113232627Sray	uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT)
1114188808Sgonzo	    | (reg & MAC_MII_REG_MASK);
1115188808Sgonzo
1116199038Sgonzo	mtx_lock(&miibus_mtx);
1117290217Sadrian	ARGE_MDIO_BARRIER_RW(sc);
1118234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
1119290217Sadrian	ARGE_MDIO_BARRIER_WRITE(sc);
1120234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
1121290217Sadrian	ARGE_MDIO_BARRIER_WRITE(sc);
1122234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
1123188808Sgonzo
1124290217Sadrian	if (arge_mdio_busy(sc) != 0) {
1125199038Sgonzo		mtx_unlock(&miibus_mtx);
1126220354Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__);
1127188808Sgonzo		/* XXX: return ERRNO istead? */
1128188808Sgonzo		return (-1);
1129188808Sgonzo	}
1130188808Sgonzo
1131290217Sadrian	ARGE_MDIO_BARRIER_READ(sc);
1132234862Sadrian	result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
1133290217Sadrian	ARGE_MDIO_BARRIER_RW(sc);
1134234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
1135199038Sgonzo	mtx_unlock(&miibus_mtx);
1136199038Sgonzo
1137232628Sray	ARGEDEBUG(sc, ARGE_DBG_MII,
1138232628Sray	    "%s: phy=%d, reg=%02x, value[%08x]=%04x\n",
1139232628Sray	    __func__, phy, reg, addr, result);
1140188808Sgonzo
1141188808Sgonzo	return (result);
1142188808Sgonzo}
1143188808Sgonzo
1144188808Sgonzostatic int
1145188808Sgonzoarge_miibus_writereg(device_t dev, int phy, int reg, int data)
1146188808Sgonzo{
1147188808Sgonzo	struct arge_softc * sc = device_get_softc(dev);
1148232627Sray	uint32_t addr =
1149196794Sgonzo	    (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK);
1150188808Sgonzo
1151234862Sadrian	ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n", __func__,
1152234862Sadrian	    phy, reg, data);
1153199038Sgonzo
1154199038Sgonzo	mtx_lock(&miibus_mtx);
1155290217Sadrian	ARGE_MDIO_BARRIER_RW(sc);
1156234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
1157290217Sadrian	ARGE_MDIO_BARRIER_WRITE(sc);
1158234862Sadrian	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CONTROL, data);
1159290217Sadrian	ARGE_MDIO_BARRIER_WRITE(sc);
1160188808Sgonzo
1161290217Sadrian	if (arge_mdio_busy(sc) != 0) {
1162290217Sadrian		mtx_unlock(&miibus_mtx);
1163220354Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s timedout\n", __func__);
1164188808Sgonzo		/* XXX: return ERRNO istead? */
1165188808Sgonzo		return (-1);
1166188808Sgonzo	}
1167188808Sgonzo
1168290217Sadrian	mtx_unlock(&miibus_mtx);
1169188808Sgonzo	return (0);
1170188808Sgonzo}
1171188808Sgonzo
1172188808Sgonzostatic void
1173188808Sgonzoarge_miibus_statchg(device_t dev)
1174188808Sgonzo{
1175232627Sray	struct arge_softc	*sc;
1176188808Sgonzo
1177188808Sgonzo	sc = device_get_softc(dev);
1178188808Sgonzo	taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task);
1179188808Sgonzo}
1180188808Sgonzo
1181188808Sgonzostatic void
1182188808Sgonzoarge_link_task(void *arg, int pending)
1183188808Sgonzo{
1184188808Sgonzo	struct arge_softc	*sc;
1185232914Sadrian	sc = (struct arge_softc *)arg;
1186232914Sadrian
1187232914Sadrian	ARGE_LOCK(sc);
1188232914Sadrian	arge_update_link_locked(sc);
1189232914Sadrian	ARGE_UNLOCK(sc);
1190232914Sadrian}
1191232914Sadrian
1192232914Sadrianstatic void
1193232914Sadrianarge_update_link_locked(struct arge_softc *sc)
1194232914Sadrian{
1195188808Sgonzo	struct mii_data		*mii;
1196188808Sgonzo	struct ifnet		*ifp;
1197199234Sgonzo	uint32_t		media, duplex;
1198188808Sgonzo
1199188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1200188808Sgonzo	ifp = sc->arge_ifp;
1201188808Sgonzo	if (mii == NULL || ifp == NULL ||
1202188808Sgonzo	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1203188808Sgonzo		return;
1204188808Sgonzo	}
1205188808Sgonzo
1206279791Sadrian	/*
1207279791Sadrian	 * If we have a static media type configured, then
1208279791Sadrian	 * use that.  Some PHY configurations (eg QCA955x -> AR8327)
1209279791Sadrian	 * use a static speed/duplex between the SoC and switch,
1210279791Sadrian	 * even though the front-facing PHY speed changes.
1211279791Sadrian	 */
1212279791Sadrian	if (sc->arge_media_type != 0) {
1213279791Sadrian		ARGEDEBUG(sc, ARGE_DBG_MII, "%s: fixed; media=%d, duplex=%d\n",
1214279791Sadrian		    __func__,
1215279791Sadrian		    sc->arge_media_type,
1216279791Sadrian		    sc->arge_duplex_mode);
1217279791Sadrian		if (mii->mii_media_status & IFM_ACTIVE) {
1218279791Sadrian			sc->arge_link_status = 1;
1219279791Sadrian		} else {
1220279791Sadrian			sc->arge_link_status = 0;
1221279791Sadrian		}
1222279791Sadrian		arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode);
1223279791Sadrian	}
1224279791Sadrian
1225188808Sgonzo	if (mii->mii_media_status & IFM_ACTIVE) {
1226188808Sgonzo
1227188808Sgonzo		media = IFM_SUBTYPE(mii->mii_media_active);
1228188808Sgonzo		if (media != IFM_NONE) {
1229188808Sgonzo			sc->arge_link_status = 1;
1230199234Sgonzo			duplex = mii->mii_media_active & IFM_GMASK;
1231234907Sadrian			ARGEDEBUG(sc, ARGE_DBG_MII, "%s: media=%d, duplex=%d\n",
1232234907Sadrian			    __func__,
1233234907Sadrian			    media,
1234234907Sadrian			    duplex);
1235199234Sgonzo			arge_set_pll(sc, media, duplex);
1236199234Sgonzo		}
1237232914Sadrian	} else {
1238199234Sgonzo		sc->arge_link_status = 0;
1239232914Sadrian	}
1240199234Sgonzo}
1241192783Sgonzo
1242199234Sgonzostatic void
1243199234Sgonzoarge_set_pll(struct arge_softc *sc, int media, int duplex)
1244199234Sgonzo{
1245211511Sadrian	uint32_t		cfg, ifcontrol, rx_filtmask;
1246234907Sadrian	uint32_t		fifo_tx, pll;
1247211511Sadrian	int if_speed;
1248192783Sgonzo
1249279791Sadrian	/*
1250279791Sadrian	 * XXX Verify - is this valid for all chips?
1251279791Sadrian	 * QCA955x (and likely some of the earlier chips!) define
1252279791Sadrian	 * this as nibble mode and byte mode, and those have to do
1253279791Sadrian	 * with the interface type (MII/SMII versus GMII/RGMII.)
1254279791Sadrian	 */
1255234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "set_pll(%04x, %s)\n", media,
1256234862Sadrian	    duplex == IFM_FDX ? "full" : "half");
1257199234Sgonzo	cfg = ARGE_READ(sc, AR71XX_MAC_CFG2);
1258232627Sray	cfg &= ~(MAC_CFG2_IFACE_MODE_1000
1259232627Sray	    | MAC_CFG2_IFACE_MODE_10_100
1260199234Sgonzo	    | MAC_CFG2_FULL_DUPLEX);
1261188808Sgonzo
1262199234Sgonzo	if (duplex == IFM_FDX)
1263199234Sgonzo		cfg |= MAC_CFG2_FULL_DUPLEX;
1264188808Sgonzo
1265199234Sgonzo	ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL);
1266199234Sgonzo	ifcontrol &= ~MAC_IFCONTROL_SPEED;
1267232627Sray	rx_filtmask =
1268199234Sgonzo	    ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK);
1269199234Sgonzo	rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE;
1270188808Sgonzo
1271199234Sgonzo	switch(media) {
1272199234Sgonzo	case IFM_10_T:
1273199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
1274211511Sadrian		if_speed = 10;
1275199234Sgonzo		break;
1276199234Sgonzo	case IFM_100_TX:
1277199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_10_100;
1278199234Sgonzo		ifcontrol |= MAC_IFCONTROL_SPEED;
1279211511Sadrian		if_speed = 100;
1280199234Sgonzo		break;
1281199234Sgonzo	case IFM_1000_T:
1282199234Sgonzo	case IFM_1000_SX:
1283199234Sgonzo		cfg |= MAC_CFG2_IFACE_MODE_1000;
1284199234Sgonzo		rx_filtmask |= FIFO_RX_MASK_BYTE_MODE;
1285211511Sadrian		if_speed = 1000;
1286199234Sgonzo		break;
1287199234Sgonzo	default:
1288211511Sadrian		if_speed = 100;
1289232627Sray		device_printf(sc->arge_dev,
1290199234Sgonzo		    "Unknown media %d\n", media);
1291199234Sgonzo	}
1292188808Sgonzo
1293234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: if_speed=%d\n", __func__, if_speed);
1294234907Sadrian
1295219589Sadrian	switch (ar71xx_soc) {
1296219589Sadrian		case AR71XX_SOC_AR7240:
1297219589Sadrian		case AR71XX_SOC_AR7241:
1298219589Sadrian		case AR71XX_SOC_AR7242:
1299249123Sadrian		case AR71XX_SOC_AR9330:
1300249123Sadrian		case AR71XX_SOC_AR9331:
1301256575Sadrian		case AR71XX_SOC_AR9341:
1302256575Sadrian		case AR71XX_SOC_AR9342:
1303256575Sadrian		case AR71XX_SOC_AR9344:
1304290910Sadrian		case AR71XX_SOC_QCA9533:
1305290910Sadrian		case AR71XX_SOC_QCA9533_V2:
1306279510Sadrian		case AR71XX_SOC_QCA9556:
1307279510Sadrian		case AR71XX_SOC_QCA9558:
1308219589Sadrian			fifo_tx = 0x01f00140;
1309219589Sadrian			break;
1310219589Sadrian		case AR71XX_SOC_AR9130:
1311219589Sadrian		case AR71XX_SOC_AR9132:
1312219589Sadrian			fifo_tx = 0x00780fff;
1313219589Sadrian			break;
1314256575Sadrian		/* AR71xx */
1315219589Sadrian		default:
1316219589Sadrian			fifo_tx = 0x008001ff;
1317219589Sadrian	}
1318188808Sgonzo
1319199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg);
1320199234Sgonzo	ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol);
1321232627Sray	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK,
1322199234Sgonzo	    rx_filtmask);
1323219589Sadrian	ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, fifo_tx);
1324188808Sgonzo
1325234919Sadrian	/* fetch PLL registers */
1326234907Sadrian	pll = ar71xx_device_get_eth_pll(sc->arge_mac_unit, if_speed);
1327234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: pll=0x%x\n", __func__, pll);
1328234907Sadrian
1329234919Sadrian	/* Override if required by platform data */
1330234919Sadrian	if (if_speed == 10 && sc->arge_pllcfg.pll_10 != 0)
1331234919Sadrian		pll = sc->arge_pllcfg.pll_10;
1332234919Sadrian	else if (if_speed == 100 && sc->arge_pllcfg.pll_100 != 0)
1333234919Sadrian		pll = sc->arge_pllcfg.pll_100;
1334234919Sadrian	else if (if_speed == 1000 && sc->arge_pllcfg.pll_1000 != 0)
1335234919Sadrian		pll = sc->arge_pllcfg.pll_1000;
1336234919Sadrian	ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: final pll=0x%x\n", __func__, pll);
1337234919Sadrian
1338234907Sadrian	/* XXX ensure pll != 0 */
1339234907Sadrian	ar71xx_device_set_pll_ge(sc->arge_mac_unit, if_speed, pll);
1340234907Sadrian
1341234907Sadrian	/* set MII registers */
1342234992Sadrian	/*
1343234992Sadrian	 * This was introduced to match what the Linux ag71xx ethernet
1344234992Sadrian	 * driver does.  For the AR71xx case, it does set the port
1345234992Sadrian	 * MII speed.  However, if this is done, non-gigabit speeds
1346234992Sadrian	 * are not at all reliable when speaking via RGMII through
1347234992Sadrian	 * 'bridge' PHY port that's pretending to be a local PHY.
1348234992Sadrian	 *
1349234992Sadrian	 * Until that gets root caused, and until an AR71xx + normal
1350234992Sadrian	 * PHY board is tested, leave this disabled.
1351234992Sadrian	 */
1352234992Sadrian#if 0
1353234907Sadrian	ar71xx_device_set_mii_speed(sc->arge_mac_unit, if_speed);
1354234992Sadrian#endif
1355188808Sgonzo}
1356188808Sgonzo
1357199234Sgonzo
1358188808Sgonzostatic void
1359188808Sgonzoarge_reset_dma(struct arge_softc *sc)
1360188808Sgonzo{
1361279791Sadrian
1362279791Sadrian	ARGEDEBUG(sc, ARGE_DBG_RESET, "%s: called\n", __func__);
1363279791Sadrian
1364188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0);
1365188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0);
1366188808Sgonzo
1367188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0);
1368188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0);
1369188808Sgonzo
1370188808Sgonzo	/* Clear all possible RX interrupts */
1371192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD)
1372188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
1373188808Sgonzo
1374232627Sray	/*
1375188808Sgonzo	 * Clear all possible TX interrupts
1376188808Sgonzo	 */
1377192569Sdwhite	while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT)
1378188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
1379188808Sgonzo
1380232627Sray	/*
1381188808Sgonzo	 * Now Rx/Tx errors
1382188808Sgonzo	 */
1383232627Sray	ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS,
1384188808Sgonzo	    DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW);
1385232627Sray	ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS,
1386188808Sgonzo	    DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN);
1387232912Sadrian
1388232912Sadrian	/*
1389232912Sadrian	 * Force a DDR flush so any pending data is properly
1390232912Sadrian	 * flushed to RAM before underlying buffers are freed.
1391232912Sadrian	 */
1392232912Sadrian	arge_flush_ddr(sc);
1393188808Sgonzo}
1394188808Sgonzo
1395188808Sgonzostatic void
1396188808Sgonzoarge_init(void *xsc)
1397188808Sgonzo{
1398188808Sgonzo	struct arge_softc	 *sc = xsc;
1399188808Sgonzo
1400188808Sgonzo	ARGE_LOCK(sc);
1401188808Sgonzo	arge_init_locked(sc);
1402188808Sgonzo	ARGE_UNLOCK(sc);
1403188808Sgonzo}
1404188808Sgonzo
1405188808Sgonzostatic void
1406188808Sgonzoarge_init_locked(struct arge_softc *sc)
1407188808Sgonzo{
1408188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
1409188808Sgonzo	struct mii_data		*mii;
1410188808Sgonzo
1411188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1412188808Sgonzo
1413255021Sloos	if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
1414255021Sloos		return;
1415188808Sgonzo
1416188808Sgonzo	/* Init circular RX list. */
1417188808Sgonzo	if (arge_rx_ring_init(sc) != 0) {
1418188808Sgonzo		device_printf(sc->arge_dev,
1419188808Sgonzo		    "initialization failed: no memory for rx buffers\n");
1420188808Sgonzo		arge_stop(sc);
1421188808Sgonzo		return;
1422188808Sgonzo	}
1423188808Sgonzo
1424188808Sgonzo	/* Init tx descriptors. */
1425188808Sgonzo	arge_tx_ring_init(sc);
1426188808Sgonzo
1427188808Sgonzo	arge_reset_dma(sc);
1428188808Sgonzo
1429199234Sgonzo	if (sc->arge_miibus) {
1430199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
1431199234Sgonzo		mii_mediachg(mii);
1432199234Sgonzo	}
1433199234Sgonzo	else {
1434199234Sgonzo		/*
1435199234Sgonzo		 * Sun always shines over multiPHY interface
1436199234Sgonzo		 */
1437199234Sgonzo		sc->arge_link_status = 1;
1438199234Sgonzo	}
1439199234Sgonzo
1440188808Sgonzo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1441188808Sgonzo	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1442188808Sgonzo
1443232914Sadrian	if (sc->arge_miibus) {
1444199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
1445232914Sadrian		arge_update_link_locked(sc);
1446232914Sadrian	}
1447192783Sgonzo
1448188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0));
1449188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0));
1450188808Sgonzo
1451188808Sgonzo	/* Start listening */
1452188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
1453188808Sgonzo
1454188808Sgonzo	/* Enable interrupts */
1455188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1456188808Sgonzo}
1457188808Sgonzo
1458188808Sgonzo/*
1459209807Sadrian * Return whether the mbuf chain is correctly aligned
1460209807Sadrian * for the arge TX engine.
1461209807Sadrian *
1462289476Sadrian * All the MACs have a length requirement: any non-final
1463289476Sadrian * fragment (ie, descriptor with MORE bit set) needs to have
1464289476Sadrian * a length divisible by 4.
1465256649Sadrian *
1466289476Sadrian * The AR71xx, AR913x require the start address also be
1467289476Sadrian * DWORD aligned.  The later MACs don't.
1468209807Sadrian */
1469209807Sadrianstatic int
1470289476Sadrianarge_mbuf_chain_is_tx_aligned(struct arge_softc *sc, struct mbuf *m0)
1471209807Sadrian{
1472209807Sadrian	struct mbuf *m;
1473209807Sadrian
1474209807Sadrian	for (m = m0; m != NULL; m = m->m_next) {
1475289476Sadrian		/*
1476289476Sadrian		 * Only do this for chips that require it.
1477289476Sadrian		 */
1478289476Sadrian		if ((sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE) &&
1479289476Sadrian		    (mtod(m, intptr_t) & 3) != 0) {
1480289476Sadrian			sc->stats.tx_pkts_unaligned_start++;
1481209807Sadrian			return 0;
1482289476Sadrian		}
1483289476Sadrian
1484289476Sadrian		/*
1485289476Sadrian		 * All chips have this requirement for length.
1486289476Sadrian		 */
1487289476Sadrian		if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0)) {
1488289476Sadrian			sc->stats.tx_pkts_unaligned_len++;
1489209807Sadrian			return 0;
1490289476Sadrian		}
1491209807Sadrian	}
1492209807Sadrian	return 1;
1493209807Sadrian}
1494209807Sadrian
1495209807Sadrian/*
1496188808Sgonzo * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
1497188808Sgonzo * pointers to the fragment pointers.
1498188808Sgonzo */
1499188808Sgonzostatic int
1500188808Sgonzoarge_encap(struct arge_softc *sc, struct mbuf **m_head)
1501188808Sgonzo{
1502188808Sgonzo	struct arge_txdesc	*txd;
1503188808Sgonzo	struct arge_desc	*desc, *prev_desc;
1504188808Sgonzo	bus_dma_segment_t	txsegs[ARGE_MAXFRAGS];
1505192569Sdwhite	int			error, i, nsegs, prod, prev_prod;
1506192783Sgonzo	struct mbuf		*m;
1507188808Sgonzo
1508188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1509188808Sgonzo
1510192783Sgonzo	/*
1511289476Sadrian	 * Fix mbuf chain based on hardware alignment constraints.
1512192783Sgonzo	 */
1513192783Sgonzo	m = *m_head;
1514289476Sadrian	if (! arge_mbuf_chain_is_tx_aligned(sc, m)) {
1515209809Sadrian		sc->stats.tx_pkts_unaligned++;
1516243882Sglebius		m = m_defrag(*m_head, M_NOWAIT);
1517192783Sgonzo		if (m == NULL) {
1518322716Sdelphij			m_freem(*m_head);
1519192783Sgonzo			*m_head = NULL;
1520192783Sgonzo			return (ENOBUFS);
1521192783Sgonzo		}
1522192783Sgonzo		*m_head = m;
1523209809Sadrian	} else
1524209809Sadrian		sc->stats.tx_pkts_aligned++;
1525192783Sgonzo
1526188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
1527188808Sgonzo	txd = &sc->arge_cdata.arge_txdesc[prod];
1528232627Sray	error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag,
1529188808Sgonzo	    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
1530188808Sgonzo
1531188808Sgonzo	if (error == EFBIG) {
1532188808Sgonzo		panic("EFBIG");
1533188808Sgonzo	} else if (error != 0)
1534188808Sgonzo		return (error);
1535188808Sgonzo
1536188808Sgonzo	if (nsegs == 0) {
1537188808Sgonzo		m_freem(*m_head);
1538188808Sgonzo		*m_head = NULL;
1539188808Sgonzo		return (EIO);
1540188808Sgonzo	}
1541188808Sgonzo
1542188808Sgonzo	/* Check number of available descriptors. */
1543290211Sadrian	if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 2)) {
1544188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
1545289476Sadrian		sc->stats.tx_pkts_nosegs++;
1546188808Sgonzo		return (ENOBUFS);
1547188808Sgonzo	}
1548188808Sgonzo
1549188808Sgonzo	txd->tx_m = *m_head;
1550188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
1551188808Sgonzo	    BUS_DMASYNC_PREWRITE);
1552188808Sgonzo
1553232627Sray	/*
1554188808Sgonzo	 * Make a list of descriptors for this packet. DMA controller will
1555188808Sgonzo	 * walk through it while arge_link is not zero.
1556290215Sadrian	 *
1557290215Sadrian	 * Since we're in a endless circular buffer, ensure that
1558290215Sadrian	 * the first descriptor in a multi-descriptor ring is always
1559290215Sadrian	 * set to EMPTY, then un-do it when we're done populating.
1560188808Sgonzo	 */
1561188808Sgonzo	prev_prod = prod;
1562188808Sgonzo	desc = prev_desc = NULL;
1563188808Sgonzo	for (i = 0; i < nsegs; i++) {
1564290215Sadrian		uint32_t tmp;
1565290215Sadrian
1566188808Sgonzo		desc = &sc->arge_rdata.arge_tx_ring[prod];
1567188808Sgonzo
1568290215Sadrian		/*
1569290215Sadrian		 * Set DESC_EMPTY so the hardware (hopefully) stops at this
1570290215Sadrian		 * point.  We don't want it to start transmitting descriptors
1571290215Sadrian		 * before we've finished fleshing this out.
1572290215Sadrian		 */
1573290215Sadrian		tmp = ARGE_DMASIZE(txsegs[i].ds_len);
1574290215Sadrian		if (i == 0)
1575290215Sadrian			tmp |= ARGE_DESC_EMPTY;
1576290215Sadrian		desc->packet_ctrl = tmp;
1577290215Sadrian
1578289476Sadrian		/* XXX Note: only relevant for older MACs; but check length! */
1579289476Sadrian		if ((sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE) &&
1580289476Sadrian		    (txsegs[i].ds_addr & 3))
1581192783Sgonzo			panic("TX packet address unaligned\n");
1582192783Sgonzo
1583188808Sgonzo		desc->packet_addr = txsegs[i].ds_addr;
1584232627Sray
1585188808Sgonzo		/* link with previous descriptor */
1586188808Sgonzo		if (prev_desc)
1587188808Sgonzo			prev_desc->packet_ctrl |= ARGE_DESC_MORE;
1588188808Sgonzo
1589188808Sgonzo		sc->arge_cdata.arge_tx_cnt++;
1590188808Sgonzo		prev_desc = desc;
1591188808Sgonzo		ARGE_INC(prod, ARGE_TX_RING_COUNT);
1592188808Sgonzo	}
1593188808Sgonzo
1594188808Sgonzo	/* Update producer index. */
1595188808Sgonzo	sc->arge_cdata.arge_tx_prod = prod;
1596188808Sgonzo
1597290215Sadrian	/*
1598290215Sadrian	 * The descriptors are updated, so enable the first one.
1599290215Sadrian	 */
1600290215Sadrian	desc = &sc->arge_rdata.arge_tx_ring[prev_prod];
1601290215Sadrian	desc->packet_ctrl &= ~ ARGE_DESC_EMPTY;
1602290215Sadrian
1603188808Sgonzo	/* Sync descriptors. */
1604188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
1605188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
1606188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1607188808Sgonzo
1608290213Sadrian	/* Flush writes */
1609290213Sadrian	ARGE_BARRIER_WRITE(sc);
1610290213Sadrian
1611188808Sgonzo	/* Start transmitting */
1612232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: setting DMA_TX_CONTROL_EN\n",
1613232628Sray	    __func__);
1614188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN);
1615188808Sgonzo	return (0);
1616188808Sgonzo}
1617188808Sgonzo
1618188808Sgonzostatic void
1619188808Sgonzoarge_start(struct ifnet *ifp)
1620188808Sgonzo{
1621188808Sgonzo	struct arge_softc	 *sc;
1622188808Sgonzo
1623188808Sgonzo	sc = ifp->if_softc;
1624188808Sgonzo
1625188808Sgonzo	ARGE_LOCK(sc);
1626188808Sgonzo	arge_start_locked(ifp);
1627188808Sgonzo	ARGE_UNLOCK(sc);
1628188808Sgonzo}
1629188808Sgonzo
1630188808Sgonzostatic void
1631188808Sgonzoarge_start_locked(struct ifnet *ifp)
1632188808Sgonzo{
1633188808Sgonzo	struct arge_softc	*sc;
1634188808Sgonzo	struct mbuf		*m_head;
1635220356Sadrian	int			enq = 0;
1636188808Sgonzo
1637188808Sgonzo	sc = ifp->if_softc;
1638188808Sgonzo
1639188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1640188808Sgonzo
1641220356Sadrian	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: beginning\n", __func__);
1642220356Sadrian
1643188808Sgonzo	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1644188808Sgonzo	    IFF_DRV_RUNNING || sc->arge_link_status == 0 )
1645188808Sgonzo		return;
1646188808Sgonzo
1647220356Sadrian	/*
1648220356Sadrian	 * Before we go any further, check whether we're already full.
1649220356Sadrian	 * The below check errors out immediately if the ring is full
1650220356Sadrian	 * and never gets a chance to set this flag. Although it's
1651220356Sadrian	 * likely never needed, this at least avoids an unexpected
1652220356Sadrian	 * situation.
1653220356Sadrian	 */
1654220356Sadrian	if (sc->arge_cdata.arge_tx_cnt >= ARGE_TX_RING_COUNT - 2) {
1655220356Sadrian		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1656232628Sray		ARGEDEBUG(sc, ARGE_DBG_ERR,
1657232628Sray		    "%s: tx_cnt %d >= max %d; setting IFF_DRV_OACTIVE\n",
1658232628Sray		    __func__, sc->arge_cdata.arge_tx_cnt,
1659232628Sray		    ARGE_TX_RING_COUNT - 2);
1660220356Sadrian		return;
1661220356Sadrian	}
1662220356Sadrian
1663188808Sgonzo	arge_flush_ddr(sc);
1664188808Sgonzo
1665188808Sgonzo	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
1666188808Sgonzo	    sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) {
1667188808Sgonzo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
1668188808Sgonzo		if (m_head == NULL)
1669188808Sgonzo			break;
1670188808Sgonzo
1671188808Sgonzo
1672188808Sgonzo		/*
1673188808Sgonzo		 * Pack the data into the transmit ring.
1674188808Sgonzo		 */
1675188808Sgonzo		if (arge_encap(sc, &m_head)) {
1676188808Sgonzo			if (m_head == NULL)
1677188808Sgonzo				break;
1678188808Sgonzo			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1679188808Sgonzo			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1680188808Sgonzo			break;
1681188808Sgonzo		}
1682188808Sgonzo
1683188808Sgonzo		enq++;
1684188808Sgonzo		/*
1685188808Sgonzo		 * If there's a BPF listener, bounce a copy of this frame
1686188808Sgonzo		 * to him.
1687188808Sgonzo		 */
1688188808Sgonzo		ETHER_BPF_MTAP(ifp, m_head);
1689188808Sgonzo	}
1690232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: finished; queued %d packets\n",
1691232628Sray	    __func__, enq);
1692188808Sgonzo}
1693188808Sgonzo
1694188808Sgonzostatic void
1695188808Sgonzoarge_stop(struct arge_softc *sc)
1696188808Sgonzo{
1697188808Sgonzo	struct ifnet	    *ifp;
1698188808Sgonzo
1699188808Sgonzo	ARGE_LOCK_ASSERT(sc);
1700188808Sgonzo
1701188808Sgonzo	ifp = sc->arge_ifp;
1702188808Sgonzo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1703199234Sgonzo	if (sc->arge_miibus)
1704199234Sgonzo		callout_stop(&sc->arge_stat_callout);
1705188808Sgonzo
1706188808Sgonzo	/* mask out interrupts */
1707188808Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1708188808Sgonzo
1709188808Sgonzo	arge_reset_dma(sc);
1710232912Sadrian
1711232912Sadrian	/* Flush FIFO and free any existing mbufs */
1712232912Sadrian	arge_flush_ddr(sc);
1713232912Sadrian	arge_rx_ring_free(sc);
1714255300Sloos	arge_tx_ring_free(sc);
1715188808Sgonzo}
1716188808Sgonzo
1717188808Sgonzo
1718188808Sgonzostatic int
1719188808Sgonzoarge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1720188808Sgonzo{
1721188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1722188808Sgonzo	struct ifreq		*ifr = (struct ifreq *) data;
1723188808Sgonzo	struct mii_data		*mii;
1724188808Sgonzo	int			error;
1725192783Sgonzo#ifdef DEVICE_POLLING
1726192783Sgonzo	int			mask;
1727192783Sgonzo#endif
1728188808Sgonzo
1729188808Sgonzo	switch (command) {
1730188808Sgonzo	case SIOCSIFFLAGS:
1731198932Sgonzo		ARGE_LOCK(sc);
1732198932Sgonzo		if ((ifp->if_flags & IFF_UP) != 0) {
1733198932Sgonzo			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1734198932Sgonzo				if (((ifp->if_flags ^ sc->arge_if_flags)
1735198939Sgonzo				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0) {
1736198939Sgonzo					/* XXX: handle promisc & multi flags */
1737198939Sgonzo				}
1738232627Sray
1739198932Sgonzo			} else {
1740198932Sgonzo				if (!sc->arge_detach)
1741198932Sgonzo					arge_init_locked(sc);
1742198932Sgonzo			}
1743198932Sgonzo		} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1744198932Sgonzo			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1745198932Sgonzo			arge_stop(sc);
1746198932Sgonzo		}
1747198932Sgonzo		sc->arge_if_flags = ifp->if_flags;
1748198932Sgonzo		ARGE_UNLOCK(sc);
1749188808Sgonzo		error = 0;
1750188808Sgonzo		break;
1751188808Sgonzo	case SIOCADDMULTI:
1752188808Sgonzo	case SIOCDELMULTI:
1753198932Sgonzo		/* XXX: implement SIOCDELMULTI */
1754188808Sgonzo		error = 0;
1755188808Sgonzo		break;
1756188808Sgonzo	case SIOCGIFMEDIA:
1757188808Sgonzo	case SIOCSIFMEDIA:
1758199234Sgonzo		if (sc->arge_miibus) {
1759199234Sgonzo			mii = device_get_softc(sc->arge_miibus);
1760232628Sray			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
1761232628Sray			    command);
1762199234Sgonzo		}
1763232627Sray		else
1764232628Sray			error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia,
1765232628Sray			    command);
1766188808Sgonzo		break;
1767198933Sgonzo	case SIOCSIFCAP:
1768198932Sgonzo		/* XXX: Check other capabilities */
1769192783Sgonzo#ifdef DEVICE_POLLING
1770198933Sgonzo		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
1771198933Sgonzo		if (mask & IFCAP_POLLING) {
1772198933Sgonzo			if (ifr->ifr_reqcap & IFCAP_POLLING) {
1773192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
1774198933Sgonzo				error = ether_poll_register(arge_poll, ifp);
1775198933Sgonzo				if (error)
1776198933Sgonzo					return error;
1777198933Sgonzo				ARGE_LOCK(sc);
1778198933Sgonzo				ifp->if_capenable |= IFCAP_POLLING;
1779198933Sgonzo				ARGE_UNLOCK(sc);
1780198933Sgonzo			} else {
1781192783Sgonzo				ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
1782198933Sgonzo				error = ether_poll_deregister(ifp);
1783198933Sgonzo				ARGE_LOCK(sc);
1784198933Sgonzo				ifp->if_capenable &= ~IFCAP_POLLING;
1785198933Sgonzo				ARGE_UNLOCK(sc);
1786198933Sgonzo			}
1787198933Sgonzo		}
1788198932Sgonzo		error = 0;
1789198933Sgonzo		break;
1790192783Sgonzo#endif
1791188808Sgonzo	default:
1792188808Sgonzo		error = ether_ioctl(ifp, command, data);
1793188808Sgonzo		break;
1794188808Sgonzo	}
1795188808Sgonzo
1796188808Sgonzo	return (error);
1797188808Sgonzo}
1798188808Sgonzo
1799188808Sgonzo/*
1800188808Sgonzo * Set media options.
1801188808Sgonzo */
1802188808Sgonzostatic int
1803188808Sgonzoarge_ifmedia_upd(struct ifnet *ifp)
1804188808Sgonzo{
1805188808Sgonzo	struct arge_softc		*sc;
1806188808Sgonzo	struct mii_data		*mii;
1807188808Sgonzo	struct mii_softc	*miisc;
1808188808Sgonzo	int			error;
1809188808Sgonzo
1810188808Sgonzo	sc = ifp->if_softc;
1811188808Sgonzo	ARGE_LOCK(sc);
1812188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1813221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1814221407Smarius		PHY_RESET(miisc);
1815188808Sgonzo	error = mii_mediachg(mii);
1816188808Sgonzo	ARGE_UNLOCK(sc);
1817188808Sgonzo
1818188808Sgonzo	return (error);
1819188808Sgonzo}
1820188808Sgonzo
1821188808Sgonzo/*
1822188808Sgonzo * Report current media status.
1823188808Sgonzo */
1824188808Sgonzostatic void
1825188808Sgonzoarge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1826188808Sgonzo{
1827188808Sgonzo	struct arge_softc		*sc = ifp->if_softc;
1828188808Sgonzo	struct mii_data		*mii;
1829188808Sgonzo
1830188808Sgonzo	mii = device_get_softc(sc->arge_miibus);
1831188808Sgonzo	ARGE_LOCK(sc);
1832188808Sgonzo	mii_pollstat(mii);
1833188808Sgonzo	ifmr->ifm_active = mii->mii_media_active;
1834188808Sgonzo	ifmr->ifm_status = mii->mii_media_status;
1835226478Syongari	ARGE_UNLOCK(sc);
1836188808Sgonzo}
1837188808Sgonzo
1838188808Sgonzostruct arge_dmamap_arg {
1839188808Sgonzo	bus_addr_t	arge_busaddr;
1840188808Sgonzo};
1841188808Sgonzo
1842188808Sgonzostatic void
1843188808Sgonzoarge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1844188808Sgonzo{
1845188808Sgonzo	struct arge_dmamap_arg	*ctx;
1846188808Sgonzo
1847188808Sgonzo	if (error != 0)
1848188808Sgonzo		return;
1849188808Sgonzo	ctx = arg;
1850188808Sgonzo	ctx->arge_busaddr = segs[0].ds_addr;
1851188808Sgonzo}
1852188808Sgonzo
1853188808Sgonzostatic int
1854188808Sgonzoarge_dma_alloc(struct arge_softc *sc)
1855188808Sgonzo{
1856188808Sgonzo	struct arge_dmamap_arg	ctx;
1857188808Sgonzo	struct arge_txdesc	*txd;
1858188808Sgonzo	struct arge_rxdesc	*rxd;
1859188808Sgonzo	int			error, i;
1860289476Sadrian	int			arge_tx_align, arge_rx_align;
1861188808Sgonzo
1862289476Sadrian	/* Assume 4 byte alignment by default */
1863289476Sadrian	arge_tx_align = 4;
1864289476Sadrian	arge_rx_align = 4;
1865289476Sadrian
1866289476Sadrian	if (sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE)
1867289476Sadrian		arge_tx_align = 1;
1868289476Sadrian	if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE)
1869289476Sadrian		arge_rx_align = 1;
1870289476Sadrian
1871188808Sgonzo	/* Create parent DMA tag. */
1872188808Sgonzo	error = bus_dma_tag_create(
1873188808Sgonzo	    bus_get_dma_tag(sc->arge_dev),	/* parent */
1874188808Sgonzo	    1, 0,			/* alignment, boundary */
1875188808Sgonzo	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1876188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1877188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1878188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
1879188808Sgonzo	    0,				/* nsegments */
1880188808Sgonzo	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1881188808Sgonzo	    0,				/* flags */
1882188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1883188808Sgonzo	    &sc->arge_cdata.arge_parent_tag);
1884188808Sgonzo	if (error != 0) {
1885232628Sray		device_printf(sc->arge_dev,
1886232628Sray		    "failed to create parent DMA tag\n");
1887188808Sgonzo		goto fail;
1888188808Sgonzo	}
1889188808Sgonzo	/* Create tag for Tx ring. */
1890188808Sgonzo	error = bus_dma_tag_create(
1891188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1892188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1893188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1894188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1895188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1896188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsize */
1897188808Sgonzo	    1,				/* nsegments */
1898188808Sgonzo	    ARGE_TX_DMA_SIZE,		/* maxsegsize */
1899188808Sgonzo	    0,				/* flags */
1900188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1901188808Sgonzo	    &sc->arge_cdata.arge_tx_ring_tag);
1902188808Sgonzo	if (error != 0) {
1903232628Sray		device_printf(sc->arge_dev,
1904232628Sray		    "failed to create Tx ring DMA tag\n");
1905188808Sgonzo		goto fail;
1906188808Sgonzo	}
1907188808Sgonzo
1908188808Sgonzo	/* Create tag for Rx ring. */
1909188808Sgonzo	error = bus_dma_tag_create(
1910188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1911188808Sgonzo	    ARGE_RING_ALIGN, 0,		/* alignment, boundary */
1912188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1913188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1914188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1915188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsize */
1916188808Sgonzo	    1,				/* nsegments */
1917188808Sgonzo	    ARGE_RX_DMA_SIZE,		/* maxsegsize */
1918188808Sgonzo	    0,				/* flags */
1919188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1920188808Sgonzo	    &sc->arge_cdata.arge_rx_ring_tag);
1921188808Sgonzo	if (error != 0) {
1922232628Sray		device_printf(sc->arge_dev,
1923232628Sray		    "failed to create Rx ring DMA tag\n");
1924188808Sgonzo		goto fail;
1925188808Sgonzo	}
1926188808Sgonzo
1927188808Sgonzo	/* Create tag for Tx buffers. */
1928188808Sgonzo	error = bus_dma_tag_create(
1929188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1930289476Sadrian	    arge_tx_align, 0,		/* alignment, boundary */
1931188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1932188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1933188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1934188808Sgonzo	    MCLBYTES * ARGE_MAXFRAGS,	/* maxsize */
1935188808Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1936188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1937188808Sgonzo	    0,				/* flags */
1938188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1939188808Sgonzo	    &sc->arge_cdata.arge_tx_tag);
1940188808Sgonzo	if (error != 0) {
1941188808Sgonzo		device_printf(sc->arge_dev, "failed to create Tx DMA tag\n");
1942188808Sgonzo		goto fail;
1943188808Sgonzo	}
1944188808Sgonzo
1945188808Sgonzo	/* Create tag for Rx buffers. */
1946188808Sgonzo	error = bus_dma_tag_create(
1947188808Sgonzo	    sc->arge_cdata.arge_parent_tag,	/* parent */
1948289476Sadrian	    arge_rx_align, 0,		/* alignment, boundary */
1949188808Sgonzo	    BUS_SPACE_MAXADDR,		/* lowaddr */
1950188808Sgonzo	    BUS_SPACE_MAXADDR,		/* highaddr */
1951188808Sgonzo	    NULL, NULL,			/* filter, filterarg */
1952188808Sgonzo	    MCLBYTES,			/* maxsize */
1953192821Sgonzo	    ARGE_MAXFRAGS,		/* nsegments */
1954188808Sgonzo	    MCLBYTES,			/* maxsegsize */
1955188808Sgonzo	    0,				/* flags */
1956188808Sgonzo	    NULL, NULL,			/* lockfunc, lockarg */
1957188808Sgonzo	    &sc->arge_cdata.arge_rx_tag);
1958188808Sgonzo	if (error != 0) {
1959188808Sgonzo		device_printf(sc->arge_dev, "failed to create Rx DMA tag\n");
1960188808Sgonzo		goto fail;
1961188808Sgonzo	}
1962188808Sgonzo
1963188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
1964188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag,
1965188808Sgonzo	    (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK |
1966232628Sray	    BUS_DMA_COHERENT | BUS_DMA_ZERO,
1967232628Sray	    &sc->arge_cdata.arge_tx_ring_map);
1968188808Sgonzo	if (error != 0) {
1969188808Sgonzo		device_printf(sc->arge_dev,
1970188808Sgonzo		    "failed to allocate DMA'able memory for Tx ring\n");
1971188808Sgonzo		goto fail;
1972188808Sgonzo	}
1973188808Sgonzo
1974188808Sgonzo	ctx.arge_busaddr = 0;
1975188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag,
1976188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring,
1977188808Sgonzo	    ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
1978188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
1979188808Sgonzo		device_printf(sc->arge_dev,
1980188808Sgonzo		    "failed to load DMA'able memory for Tx ring\n");
1981188808Sgonzo		goto fail;
1982188808Sgonzo	}
1983188808Sgonzo	sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr;
1984188808Sgonzo
1985188808Sgonzo	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
1986188808Sgonzo	error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag,
1987188808Sgonzo	    (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK |
1988232628Sray	    BUS_DMA_COHERENT | BUS_DMA_ZERO,
1989232628Sray	    &sc->arge_cdata.arge_rx_ring_map);
1990188808Sgonzo	if (error != 0) {
1991188808Sgonzo		device_printf(sc->arge_dev,
1992188808Sgonzo		    "failed to allocate DMA'able memory for Rx ring\n");
1993188808Sgonzo		goto fail;
1994188808Sgonzo	}
1995188808Sgonzo
1996188808Sgonzo	ctx.arge_busaddr = 0;
1997188808Sgonzo	error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag,
1998188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring,
1999188808Sgonzo	    ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0);
2000188808Sgonzo	if (error != 0 || ctx.arge_busaddr == 0) {
2001188808Sgonzo		device_printf(sc->arge_dev,
2002188808Sgonzo		    "failed to load DMA'able memory for Rx ring\n");
2003188808Sgonzo		goto fail;
2004188808Sgonzo	}
2005188808Sgonzo	sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr;
2006188808Sgonzo
2007188808Sgonzo	/* Create DMA maps for Tx buffers. */
2008188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2009188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
2010188808Sgonzo		txd->tx_m = NULL;
2011188808Sgonzo		txd->tx_dmamap = NULL;
2012188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0,
2013188808Sgonzo		    &txd->tx_dmamap);
2014188808Sgonzo		if (error != 0) {
2015188808Sgonzo			device_printf(sc->arge_dev,
2016188808Sgonzo			    "failed to create Tx dmamap\n");
2017188808Sgonzo			goto fail;
2018188808Sgonzo		}
2019188808Sgonzo	}
2020188808Sgonzo	/* Create DMA maps for Rx buffers. */
2021188808Sgonzo	if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
2022188808Sgonzo	    &sc->arge_cdata.arge_rx_sparemap)) != 0) {
2023188808Sgonzo		device_printf(sc->arge_dev,
2024188808Sgonzo		    "failed to create spare Rx dmamap\n");
2025188808Sgonzo		goto fail;
2026188808Sgonzo	}
2027188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2028188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
2029188808Sgonzo		rxd->rx_m = NULL;
2030188808Sgonzo		rxd->rx_dmamap = NULL;
2031188808Sgonzo		error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0,
2032188808Sgonzo		    &rxd->rx_dmamap);
2033188808Sgonzo		if (error != 0) {
2034188808Sgonzo			device_printf(sc->arge_dev,
2035188808Sgonzo			    "failed to create Rx dmamap\n");
2036188808Sgonzo			goto fail;
2037188808Sgonzo		}
2038188808Sgonzo	}
2039188808Sgonzo
2040188808Sgonzofail:
2041188808Sgonzo	return (error);
2042188808Sgonzo}
2043188808Sgonzo
2044188808Sgonzostatic void
2045188808Sgonzoarge_dma_free(struct arge_softc *sc)
2046188808Sgonzo{
2047188808Sgonzo	struct arge_txdesc	*txd;
2048188808Sgonzo	struct arge_rxdesc	*rxd;
2049188808Sgonzo	int			i;
2050188808Sgonzo
2051188808Sgonzo	/* Tx ring. */
2052188808Sgonzo	if (sc->arge_cdata.arge_tx_ring_tag) {
2053267363Sjhb		if (sc->arge_rdata.arge_tx_ring_paddr)
2054188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag,
2055188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
2056267363Sjhb		if (sc->arge_rdata.arge_tx_ring)
2057188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag,
2058188808Sgonzo			    sc->arge_rdata.arge_tx_ring,
2059188808Sgonzo			    sc->arge_cdata.arge_tx_ring_map);
2060188808Sgonzo		sc->arge_rdata.arge_tx_ring = NULL;
2061267363Sjhb		sc->arge_rdata.arge_tx_ring_paddr = 0;
2062188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag);
2063188808Sgonzo		sc->arge_cdata.arge_tx_ring_tag = NULL;
2064188808Sgonzo	}
2065188808Sgonzo	/* Rx ring. */
2066188808Sgonzo	if (sc->arge_cdata.arge_rx_ring_tag) {
2067267363Sjhb		if (sc->arge_rdata.arge_rx_ring_paddr)
2068188808Sgonzo			bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag,
2069188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
2070267363Sjhb		if (sc->arge_rdata.arge_rx_ring)
2071188808Sgonzo			bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag,
2072188808Sgonzo			    sc->arge_rdata.arge_rx_ring,
2073188808Sgonzo			    sc->arge_cdata.arge_rx_ring_map);
2074188808Sgonzo		sc->arge_rdata.arge_rx_ring = NULL;
2075267363Sjhb		sc->arge_rdata.arge_rx_ring_paddr = 0;
2076188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag);
2077188808Sgonzo		sc->arge_cdata.arge_rx_ring_tag = NULL;
2078188808Sgonzo	}
2079188808Sgonzo	/* Tx buffers. */
2080188808Sgonzo	if (sc->arge_cdata.arge_tx_tag) {
2081188808Sgonzo		for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2082188808Sgonzo			txd = &sc->arge_cdata.arge_txdesc[i];
2083188808Sgonzo			if (txd->tx_dmamap) {
2084188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag,
2085188808Sgonzo				    txd->tx_dmamap);
2086188808Sgonzo				txd->tx_dmamap = NULL;
2087188808Sgonzo			}
2088188808Sgonzo		}
2089188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag);
2090188808Sgonzo		sc->arge_cdata.arge_tx_tag = NULL;
2091188808Sgonzo	}
2092188808Sgonzo	/* Rx buffers. */
2093188808Sgonzo	if (sc->arge_cdata.arge_rx_tag) {
2094188808Sgonzo		for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2095188808Sgonzo			rxd = &sc->arge_cdata.arge_rxdesc[i];
2096188808Sgonzo			if (rxd->rx_dmamap) {
2097188808Sgonzo				bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
2098188808Sgonzo				    rxd->rx_dmamap);
2099188808Sgonzo				rxd->rx_dmamap = NULL;
2100188808Sgonzo			}
2101188808Sgonzo		}
2102188808Sgonzo		if (sc->arge_cdata.arge_rx_sparemap) {
2103188808Sgonzo			bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag,
2104188808Sgonzo			    sc->arge_cdata.arge_rx_sparemap);
2105188808Sgonzo			sc->arge_cdata.arge_rx_sparemap = 0;
2106188808Sgonzo		}
2107188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag);
2108188808Sgonzo		sc->arge_cdata.arge_rx_tag = NULL;
2109188808Sgonzo	}
2110188808Sgonzo
2111188808Sgonzo	if (sc->arge_cdata.arge_parent_tag) {
2112188808Sgonzo		bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag);
2113188808Sgonzo		sc->arge_cdata.arge_parent_tag = NULL;
2114188808Sgonzo	}
2115188808Sgonzo}
2116188808Sgonzo
2117188808Sgonzo/*
2118188808Sgonzo * Initialize the transmit descriptors.
2119188808Sgonzo */
2120188808Sgonzostatic int
2121188808Sgonzoarge_tx_ring_init(struct arge_softc *sc)
2122188808Sgonzo{
2123188808Sgonzo	struct arge_ring_data	*rd;
2124188808Sgonzo	struct arge_txdesc	*txd;
2125188808Sgonzo	bus_addr_t		addr;
2126188808Sgonzo	int			i;
2127188808Sgonzo
2128188808Sgonzo	sc->arge_cdata.arge_tx_prod = 0;
2129188808Sgonzo	sc->arge_cdata.arge_tx_cons = 0;
2130188808Sgonzo	sc->arge_cdata.arge_tx_cnt = 0;
2131188808Sgonzo
2132188808Sgonzo	rd = &sc->arge_rdata;
2133323205Semaste	bzero(rd->arge_tx_ring, sizeof(*rd->arge_tx_ring));
2134188808Sgonzo	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2135188808Sgonzo		if (i == ARGE_TX_RING_COUNT - 1)
2136188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, 0);
2137188808Sgonzo		else
2138188808Sgonzo			addr = ARGE_TX_RING_ADDR(sc, i + 1);
2139188808Sgonzo		rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY;
2140188808Sgonzo		rd->arge_tx_ring[i].next_desc = addr;
2141188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[i];
2142188808Sgonzo		txd->tx_m = NULL;
2143188808Sgonzo	}
2144188808Sgonzo
2145188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
2146188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
2147188808Sgonzo	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2148188808Sgonzo
2149188808Sgonzo	return (0);
2150188808Sgonzo}
2151188808Sgonzo
2152188808Sgonzo/*
2153255300Sloos * Free the Tx ring, unload any pending dma transaction and free the mbuf.
2154255300Sloos */
2155255300Sloosstatic void
2156255300Sloosarge_tx_ring_free(struct arge_softc *sc)
2157255300Sloos{
2158255300Sloos	struct arge_txdesc	*txd;
2159255300Sloos	int			i;
2160255300Sloos
2161255300Sloos	/* Free the Tx buffers. */
2162255300Sloos	for (i = 0; i < ARGE_TX_RING_COUNT; i++) {
2163255300Sloos		txd = &sc->arge_cdata.arge_txdesc[i];
2164255300Sloos		if (txd->tx_dmamap) {
2165255300Sloos			bus_dmamap_sync(sc->arge_cdata.arge_tx_tag,
2166255300Sloos			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
2167255300Sloos			bus_dmamap_unload(sc->arge_cdata.arge_tx_tag,
2168255300Sloos			    txd->tx_dmamap);
2169255300Sloos		}
2170255300Sloos		if (txd->tx_m)
2171255300Sloos			m_freem(txd->tx_m);
2172255300Sloos		txd->tx_m = NULL;
2173255300Sloos	}
2174255300Sloos}
2175255300Sloos
2176255300Sloos/*
2177188808Sgonzo * Initialize the RX descriptors and allocate mbufs for them. Note that
2178188808Sgonzo * we arrange the descriptors in a closed ring, so that the last descriptor
2179188808Sgonzo * points back to the first.
2180188808Sgonzo */
2181188808Sgonzostatic int
2182188808Sgonzoarge_rx_ring_init(struct arge_softc *sc)
2183188808Sgonzo{
2184188808Sgonzo	struct arge_ring_data	*rd;
2185188808Sgonzo	struct arge_rxdesc	*rxd;
2186188808Sgonzo	bus_addr_t		addr;
2187188808Sgonzo	int			i;
2188188808Sgonzo
2189188808Sgonzo	sc->arge_cdata.arge_rx_cons = 0;
2190188808Sgonzo
2191188808Sgonzo	rd = &sc->arge_rdata;
2192323205Semaste	bzero(rd->arge_rx_ring, sizeof(*rd->arge_rx_ring));
2193188808Sgonzo	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2194188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[i];
2195232912Sadrian		if (rxd->rx_m != NULL) {
2196232912Sadrian			device_printf(sc->arge_dev,
2197232912Sadrian			    "%s: ring[%d] rx_m wasn't free?\n",
2198232912Sadrian			    __func__,
2199232912Sadrian			    i);
2200232912Sadrian		}
2201188808Sgonzo		rxd->rx_m = NULL;
2202188808Sgonzo		rxd->desc = &rd->arge_rx_ring[i];
2203188808Sgonzo		if (i == ARGE_RX_RING_COUNT - 1)
2204188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, 0);
2205188808Sgonzo		else
2206188808Sgonzo			addr = ARGE_RX_RING_ADDR(sc, i + 1);
2207188808Sgonzo		rd->arge_rx_ring[i].next_desc = addr;
2208192783Sgonzo		if (arge_newbuf(sc, i) != 0) {
2209188808Sgonzo			return (ENOBUFS);
2210192783Sgonzo		}
2211188808Sgonzo	}
2212188808Sgonzo
2213188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2214188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
2215195434Sgonzo	    BUS_DMASYNC_PREWRITE);
2216188808Sgonzo
2217188808Sgonzo	return (0);
2218188808Sgonzo}
2219188808Sgonzo
2220188808Sgonzo/*
2221232912Sadrian * Free all the buffers in the RX ring.
2222232912Sadrian *
2223232912Sadrian * TODO: ensure that DMA is disabled and no pending DMA
2224232912Sadrian * is lurking in the FIFO.
2225232912Sadrian */
2226232912Sadrianstatic void
2227232912Sadrianarge_rx_ring_free(struct arge_softc *sc)
2228232912Sadrian{
2229232912Sadrian	int i;
2230232912Sadrian	struct arge_rxdesc	*rxd;
2231232912Sadrian
2232232912Sadrian	ARGE_LOCK_ASSERT(sc);
2233232912Sadrian
2234232912Sadrian	for (i = 0; i < ARGE_RX_RING_COUNT; i++) {
2235232912Sadrian		rxd = &sc->arge_cdata.arge_rxdesc[i];
2236232912Sadrian		/* Unmap the mbuf */
2237232912Sadrian		if (rxd->rx_m != NULL) {
2238232912Sadrian			bus_dmamap_unload(sc->arge_cdata.arge_rx_tag,
2239232912Sadrian			    rxd->rx_dmamap);
2240232912Sadrian			m_free(rxd->rx_m);
2241232912Sadrian			rxd->rx_m = NULL;
2242232912Sadrian		}
2243232912Sadrian	}
2244232912Sadrian}
2245232912Sadrian
2246232912Sadrian/*
2247188808Sgonzo * Initialize an RX descriptor and attach an MBUF cluster.
2248188808Sgonzo */
2249188808Sgonzostatic int
2250188808Sgonzoarge_newbuf(struct arge_softc *sc, int idx)
2251188808Sgonzo{
2252188808Sgonzo	struct arge_desc		*desc;
2253188808Sgonzo	struct arge_rxdesc	*rxd;
2254188808Sgonzo	struct mbuf		*m;
2255188808Sgonzo	bus_dma_segment_t	segs[1];
2256188808Sgonzo	bus_dmamap_t		map;
2257188808Sgonzo	int			nsegs;
2258188808Sgonzo
2259289671Sadrian	/* XXX TODO: should just allocate an explicit 2KiB buffer */
2260243882Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
2261188808Sgonzo	if (m == NULL)
2262188808Sgonzo		return (ENOBUFS);
2263188808Sgonzo	m->m_len = m->m_pkthdr.len = MCLBYTES;
2264289476Sadrian
2265289476Sadrian	/*
2266289476Sadrian	 * Add extra space to "adjust" (copy) the packet back to be aligned
2267289476Sadrian	 * for purposes of IPv4/IPv6 header contents.
2268289476Sadrian	 */
2269289671Sadrian	if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE)
2270289671Sadrian		m_adj(m, sizeof(uint64_t));
2271289671Sadrian	/*
2272289671Sadrian	 * If it's a 1-byte aligned buffer, then just offset it two bytes
2273289671Sadrian	 * and that will give us a hopefully correctly DWORD aligned
2274289671Sadrian	 * L3 payload - and we won't have to undo it afterwards.
2275289671Sadrian	 */
2276289671Sadrian	else if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE)
2277289671Sadrian		m_adj(m, sizeof(uint16_t));
2278188808Sgonzo
2279188808Sgonzo	if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag,
2280188808Sgonzo	    sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) {
2281188808Sgonzo		m_freem(m);
2282188808Sgonzo		return (ENOBUFS);
2283188808Sgonzo	}
2284188808Sgonzo	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
2285188808Sgonzo
2286188808Sgonzo	rxd = &sc->arge_cdata.arge_rxdesc[idx];
2287188808Sgonzo	if (rxd->rx_m != NULL) {
2288188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap);
2289188808Sgonzo	}
2290188808Sgonzo	map = rxd->rx_dmamap;
2291188808Sgonzo	rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap;
2292188808Sgonzo	sc->arge_cdata.arge_rx_sparemap = map;
2293188808Sgonzo	rxd->rx_m = m;
2294188808Sgonzo	desc = rxd->desc;
2295289476Sadrian	if ((sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE) &&
2296289476Sadrian	    segs[0].ds_addr & 3)
2297192783Sgonzo		panic("RX packet address unaligned");
2298188808Sgonzo	desc->packet_addr = segs[0].ds_addr;
2299192783Sgonzo	desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len);
2300188808Sgonzo
2301195434Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2302195434Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
2303195434Sgonzo	    BUS_DMASYNC_PREWRITE);
2304195434Sgonzo
2305188808Sgonzo	return (0);
2306188808Sgonzo}
2307188808Sgonzo
2308289671Sadrian/*
2309289671Sadrian * Move the data backwards 16 bits to (hopefully!) ensure the
2310289671Sadrian * IPv4/IPv6 payload is aligned.
2311289671Sadrian *
2312289671Sadrian * This is required for earlier hardware where the RX path
2313289671Sadrian * requires DWORD aligned buffers.
2314289671Sadrian */
2315188808Sgonzostatic __inline void
2316188808Sgonzoarge_fixup_rx(struct mbuf *m)
2317188808Sgonzo{
2318198933Sgonzo	int		i;
2319198933Sgonzo	uint16_t	*src, *dst;
2320188808Sgonzo
2321188808Sgonzo	src = mtod(m, uint16_t *);
2322188808Sgonzo	dst = src - 1;
2323188808Sgonzo
2324195434Sgonzo	for (i = 0; i < m->m_len / sizeof(uint16_t); i++) {
2325188808Sgonzo		*dst++ = *src++;
2326195434Sgonzo	}
2327188808Sgonzo
2328195434Sgonzo	if (m->m_len % sizeof(uint16_t))
2329195434Sgonzo		*(uint8_t *)dst = *(uint8_t *)src;
2330195434Sgonzo
2331188808Sgonzo	m->m_data -= ETHER_ALIGN;
2332188808Sgonzo}
2333188808Sgonzo
2334192783Sgonzo#ifdef DEVICE_POLLING
2335198667Sgonzostatic int
2336192783Sgonzoarge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
2337192783Sgonzo{
2338192783Sgonzo	struct arge_softc *sc = ifp->if_softc;
2339198667Sgonzo	int rx_npkts = 0;
2340188808Sgonzo
2341198933Sgonzo	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2342192783Sgonzo		ARGE_LOCK(sc);
2343192783Sgonzo		arge_tx_locked(sc);
2344198667Sgonzo		rx_npkts = arge_rx_locked(sc);
2345192783Sgonzo		ARGE_UNLOCK(sc);
2346198933Sgonzo	}
2347198667Sgonzo
2348198667Sgonzo	return (rx_npkts);
2349192783Sgonzo}
2350192783Sgonzo#endif /* DEVICE_POLLING */
2351192783Sgonzo
2352192783Sgonzo
2353188808Sgonzostatic void
2354188808Sgonzoarge_tx_locked(struct arge_softc *sc)
2355188808Sgonzo{
2356188808Sgonzo	struct arge_txdesc	*txd;
2357188808Sgonzo	struct arge_desc	*cur_tx;
2358188808Sgonzo	struct ifnet		*ifp;
2359188808Sgonzo	uint32_t		ctrl;
2360188808Sgonzo	int			cons, prod;
2361188808Sgonzo
2362188808Sgonzo	ARGE_LOCK_ASSERT(sc);
2363188808Sgonzo
2364188808Sgonzo	cons = sc->arge_cdata.arge_tx_cons;
2365188808Sgonzo	prod = sc->arge_cdata.arge_tx_prod;
2366220356Sadrian
2367232628Sray	ARGEDEBUG(sc, ARGE_DBG_TX, "%s: cons=%d, prod=%d\n", __func__, cons,
2368232628Sray	    prod);
2369220356Sadrian
2370188808Sgonzo	if (cons == prod)
2371188808Sgonzo		return;
2372188808Sgonzo
2373188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
2374188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map,
2375188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2376188808Sgonzo
2377188808Sgonzo	ifp = sc->arge_ifp;
2378188808Sgonzo	/*
2379188808Sgonzo	 * Go through our tx list and free mbufs for those
2380188808Sgonzo	 * frames that have been transmitted.
2381188808Sgonzo	 */
2382188808Sgonzo	for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) {
2383188808Sgonzo		cur_tx = &sc->arge_rdata.arge_tx_ring[cons];
2384188808Sgonzo		ctrl = cur_tx->packet_ctrl;
2385188808Sgonzo		/* Check if descriptor has "finished" flag */
2386188808Sgonzo		if ((ctrl & ARGE_DESC_EMPTY) == 0)
2387188808Sgonzo			break;
2388188808Sgonzo
2389188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT);
2390188808Sgonzo
2391188808Sgonzo		sc->arge_cdata.arge_tx_cnt--;
2392188808Sgonzo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2393188808Sgonzo
2394188808Sgonzo		txd = &sc->arge_cdata.arge_txdesc[cons];
2395188808Sgonzo
2396271858Sglebius		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
2397188808Sgonzo
2398188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap,
2399188808Sgonzo		    BUS_DMASYNC_POSTWRITE);
2400188808Sgonzo		bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap);
2401188808Sgonzo
2402188808Sgonzo		/* Free only if it's first descriptor in list */
2403188808Sgonzo		if (txd->tx_m)
2404188808Sgonzo			m_freem(txd->tx_m);
2405188808Sgonzo		txd->tx_m = NULL;
2406188808Sgonzo
2407188808Sgonzo		/* reset descriptor */
2408188808Sgonzo		cur_tx->packet_addr = 0;
2409188808Sgonzo	}
2410188808Sgonzo
2411188808Sgonzo	sc->arge_cdata.arge_tx_cons = cons;
2412188808Sgonzo
2413188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag,
2414188808Sgonzo	    sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE);
2415188808Sgonzo}
2416188808Sgonzo
2417188808Sgonzo
2418198667Sgonzostatic int
2419188808Sgonzoarge_rx_locked(struct arge_softc *sc)
2420188808Sgonzo{
2421188808Sgonzo	struct arge_rxdesc	*rxd;
2422188808Sgonzo	struct ifnet		*ifp = sc->arge_ifp;
2423192783Sgonzo	int			cons, prog, packet_len, i;
2424188808Sgonzo	struct arge_desc	*cur_rx;
2425188808Sgonzo	struct mbuf		*m;
2426198667Sgonzo	int			rx_npkts = 0;
2427188808Sgonzo
2428188808Sgonzo	ARGE_LOCK_ASSERT(sc);
2429188808Sgonzo
2430188808Sgonzo	cons = sc->arge_cdata.arge_rx_cons;
2431188808Sgonzo
2432188808Sgonzo	bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2433188808Sgonzo	    sc->arge_cdata.arge_rx_ring_map,
2434188808Sgonzo	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2435188808Sgonzo
2436232627Sray	for (prog = 0; prog < ARGE_RX_RING_COUNT;
2437188808Sgonzo	    ARGE_INC(cons, ARGE_RX_RING_COUNT)) {
2438188808Sgonzo		cur_rx = &sc->arge_rdata.arge_rx_ring[cons];
2439188808Sgonzo		rxd = &sc->arge_cdata.arge_rxdesc[cons];
2440188808Sgonzo		m = rxd->rx_m;
2441188808Sgonzo
2442188808Sgonzo		if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0)
2443232627Sray		       break;
2444188808Sgonzo
2445188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD);
2446188808Sgonzo
2447188808Sgonzo		prog++;
2448188808Sgonzo
2449188808Sgonzo		packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl);
2450188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap,
2451195434Sgonzo		    BUS_DMASYNC_POSTREAD);
2452188808Sgonzo		m = rxd->rx_m;
2453188808Sgonzo
2454289671Sadrian		/*
2455289671Sadrian		 * If the MAC requires 4 byte alignment then the RX setup
2456289671Sadrian		 * routine will have pre-offset things; so un-offset it here.
2457289671Sadrian		 */
2458289671Sadrian		if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE)
2459289671Sadrian			arge_fixup_rx(m);
2460289671Sadrian
2461188808Sgonzo		m->m_pkthdr.rcvif = ifp;
2462188808Sgonzo		/* Skip 4 bytes of CRC */
2463188808Sgonzo		m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
2464271858Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
2465198667Sgonzo		rx_npkts++;
2466188808Sgonzo
2467188808Sgonzo		ARGE_UNLOCK(sc);
2468188808Sgonzo		(*ifp->if_input)(ifp, m);
2469188808Sgonzo		ARGE_LOCK(sc);
2470192783Sgonzo		cur_rx->packet_addr = 0;
2471192783Sgonzo	}
2472188808Sgonzo
2473192783Sgonzo	if (prog > 0) {
2474192783Sgonzo
2475192783Sgonzo		i = sc->arge_cdata.arge_rx_cons;
2476192783Sgonzo		for (; prog > 0 ; prog--) {
2477192783Sgonzo			if (arge_newbuf(sc, i) != 0) {
2478232627Sray				device_printf(sc->arge_dev,
2479192783Sgonzo				    "Failed to allocate buffer\n");
2480192783Sgonzo				break;
2481192783Sgonzo			}
2482192783Sgonzo			ARGE_INC(i, ARGE_RX_RING_COUNT);
2483188808Sgonzo		}
2484188808Sgonzo
2485188808Sgonzo		bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag,
2486188808Sgonzo		    sc->arge_cdata.arge_rx_ring_map,
2487195434Sgonzo		    BUS_DMASYNC_PREWRITE);
2488188808Sgonzo
2489188808Sgonzo		sc->arge_cdata.arge_rx_cons = cons;
2490188808Sgonzo	}
2491198667Sgonzo
2492198667Sgonzo	return (rx_npkts);
2493188808Sgonzo}
2494188808Sgonzo
2495188808Sgonzostatic int
2496188808Sgonzoarge_intr_filter(void *arg)
2497188808Sgonzo{
2498188808Sgonzo	struct arge_softc	*sc = arg;
2499188808Sgonzo	uint32_t		status, ints;
2500188808Sgonzo
2501188808Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
2502188808Sgonzo	ints = ARGE_READ(sc, AR71XX_DMA_INTR);
2503188808Sgonzo
2504220354Sadrian	ARGEDEBUG(sc, ARGE_DBG_INTR, "int mask(filter) = %b\n", ints,
2505188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
2506188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
2507232627Sray	ARGEDEBUG(sc, ARGE_DBG_INTR, "status(filter) = %b\n", status,
2508188808Sgonzo	    "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD"
2509188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
2510188808Sgonzo
2511188808Sgonzo	if (status & DMA_INTR_ALL) {
2512191644Sgonzo		sc->arge_intr_status |= status;
2513192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_INTR, 0);
2514289476Sadrian		sc->stats.intr_ok++;
2515188808Sgonzo		return (FILTER_SCHEDULE_THREAD);
2516232627Sray	}
2517188808Sgonzo
2518188808Sgonzo	sc->arge_intr_status = 0;
2519289476Sadrian	sc->stats.intr_stray++;
2520188808Sgonzo	return (FILTER_STRAY);
2521188808Sgonzo}
2522188808Sgonzo
2523188808Sgonzostatic void
2524188808Sgonzoarge_intr(void *arg)
2525188808Sgonzo{
2526188808Sgonzo	struct arge_softc	*sc = arg;
2527188808Sgonzo	uint32_t		status;
2528220356Sadrian	struct ifnet		*ifp = sc->arge_ifp;
2529290090Sadrian#ifdef	ARGE_DEBUG
2530290090Sadrian	int i;
2531290090Sadrian#endif
2532188808Sgonzo
2533192783Sgonzo	status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS);
2534192783Sgonzo	status |= sc->arge_intr_status;
2535188808Sgonzo
2536232627Sray	ARGEDEBUG(sc, ARGE_DBG_INTR, "int status(intr) = %b\n", status,
2537188808Sgonzo	    "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD"
2538188808Sgonzo	    "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT");
2539188808Sgonzo
2540232627Sray	/*
2541232627Sray	 * Is it our interrupt at all?
2542188808Sgonzo	 */
2543289476Sadrian	if (status == 0) {
2544289476Sadrian		sc->stats.intr_stray2++;
2545188808Sgonzo		return;
2546289476Sadrian	}
2547188808Sgonzo
2548290090Sadrian#ifdef	ARGE_DEBUG
2549290090Sadrian	for (i = 0; i < 32; i++) {
2550290214Sadrian		if (status & (1U << i)) {
2551290123Sadrian			sc->intr_stats.count[i]++;
2552290090Sadrian		}
2553290090Sadrian	}
2554290090Sadrian#endif
2555290090Sadrian
2556188808Sgonzo	if (status & DMA_INTR_RX_BUS_ERROR) {
2557188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR);
2558188808Sgonzo		device_printf(sc->arge_dev, "RX bus error");
2559188808Sgonzo		return;
2560188808Sgonzo	}
2561188808Sgonzo
2562188808Sgonzo	if (status & DMA_INTR_TX_BUS_ERROR) {
2563188808Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR);
2564188808Sgonzo		device_printf(sc->arge_dev, "TX bus error");
2565188808Sgonzo		return;
2566188808Sgonzo	}
2567188808Sgonzo
2568192783Sgonzo	ARGE_LOCK(sc);
2569285121Sadrian	arge_flush_ddr(sc);
2570188808Sgonzo
2571192783Sgonzo	if (status & DMA_INTR_RX_PKT_RCVD)
2572192783Sgonzo		arge_rx_locked(sc);
2573188808Sgonzo
2574232627Sray	/*
2575232627Sray	 * RX overrun disables the receiver.
2576232627Sray	 * Clear indication and re-enable rx.
2577192783Sgonzo	 */
2578192783Sgonzo	if ( status & DMA_INTR_RX_OVERFLOW) {
2579192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW);
2580192783Sgonzo		ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN);
2581220356Sadrian		sc->stats.rx_overflow++;
2582192783Sgonzo	}
2583188808Sgonzo
2584192783Sgonzo	if (status & DMA_INTR_TX_PKT_SENT)
2585192783Sgonzo		arge_tx_locked(sc);
2586232627Sray	/*
2587232627Sray	 * Underrun turns off TX. Clear underrun indication.
2588232627Sray	 * If there's anything left in the ring, reactivate the tx.
2589192783Sgonzo	 */
2590192569Sdwhite	if (status & DMA_INTR_TX_UNDERRUN) {
2591192569Sdwhite		ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN);
2592220356Sadrian		sc->stats.tx_underflow++;
2593232628Sray		ARGEDEBUG(sc, ARGE_DBG_TX, "%s: TX underrun; tx_cnt=%d\n",
2594232628Sray		    __func__, sc->arge_cdata.arge_tx_cnt);
2595219590Sadrian		if (sc->arge_cdata.arge_tx_cnt > 0 ) {
2596232627Sray			ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL,
2597192783Sgonzo			    DMA_TX_CONTROL_EN);
2598192783Sgonzo		}
2599192569Sdwhite	}
2600192569Sdwhite
2601192946Sgonzo	/*
2602220357Sadrian	 * If we've finished TXing and there's space for more packets
2603220357Sadrian	 * to be queued for TX, do so. Otherwise we may end up in a
2604220357Sadrian	 * situation where the interface send queue was filled
2605220357Sadrian	 * whilst the hardware queue was full, then the hardware
2606220357Sadrian	 * queue was drained by the interface send queue wasn't,
2607220357Sadrian	 * and thus if_start() is never called to kick-start
2608220357Sadrian	 * the send process (and all subsequent packets are simply
2609220357Sadrian	 * discarded.
2610220357Sadrian	 *
2611220357Sadrian	 * XXX TODO: make sure that the hardware deals nicely
2612220357Sadrian	 * with the possibility of the queue being enabled above
2613220357Sadrian	 * after a TX underrun, then having the hardware queue added
2614220357Sadrian	 * to below.
2615220357Sadrian	 */
2616220357Sadrian	if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) &&
2617220357Sadrian	    (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
2618220357Sadrian		if (!IFQ_IS_EMPTY(&ifp->if_snd))
2619220357Sadrian			arge_start_locked(ifp);
2620220357Sadrian	}
2621220357Sadrian
2622220357Sadrian	/*
2623192946Sgonzo	 * We handled all bits, clear status
2624192946Sgonzo	 */
2625192946Sgonzo	sc->arge_intr_status = 0;
2626188808Sgonzo	ARGE_UNLOCK(sc);
2627192783Sgonzo	/*
2628232627Sray	 * re-enable all interrupts
2629192783Sgonzo	 */
2630192783Sgonzo	ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL);
2631188808Sgonzo}
2632188808Sgonzo
2633192783Sgonzo
2634188808Sgonzostatic void
2635188808Sgonzoarge_tick(void *xsc)
2636188808Sgonzo{
2637188808Sgonzo	struct arge_softc	*sc = xsc;
2638188808Sgonzo	struct mii_data		*mii;
2639188808Sgonzo
2640188808Sgonzo	ARGE_LOCK_ASSERT(sc);
2641188808Sgonzo
2642199234Sgonzo	if (sc->arge_miibus) {
2643199234Sgonzo		mii = device_get_softc(sc->arge_miibus);
2644199234Sgonzo		mii_tick(mii);
2645199234Sgonzo		callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc);
2646199234Sgonzo	}
2647188808Sgonzo}
2648199234Sgonzo
2649199234Sgonzoint
2650199234Sgonzoarge_multiphy_mediachange(struct ifnet *ifp)
2651199234Sgonzo{
2652199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
2653199234Sgonzo	struct ifmedia *ifm = &sc->arge_ifmedia;
2654199234Sgonzo	struct ifmedia_entry *ife = ifm->ifm_cur;
2655199234Sgonzo
2656199234Sgonzo	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
2657199234Sgonzo		return (EINVAL);
2658199234Sgonzo
2659199234Sgonzo	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
2660232627Sray		device_printf(sc->arge_dev,
2661199234Sgonzo		    "AUTO is not supported for multiphy MAC");
2662199234Sgonzo		return (EINVAL);
2663199234Sgonzo	}
2664199234Sgonzo
2665199234Sgonzo	/*
2666199234Sgonzo	 * Ignore everything
2667199234Sgonzo	 */
2668199234Sgonzo	return (0);
2669199234Sgonzo}
2670199234Sgonzo
2671199234Sgonzovoid
2672199234Sgonzoarge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
2673199234Sgonzo{
2674199234Sgonzo	struct arge_softc *sc = ifp->if_softc;
2675199234Sgonzo
2676199234Sgonzo	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
2677232627Sray	ifmr->ifm_active = IFM_ETHER | sc->arge_media_type |
2678199234Sgonzo	    sc->arge_duplex_mode;
2679199234Sgonzo}
2680199234Sgonzo
2681234862Sadrian#if defined(ARGE_MDIO)
2682234862Sadrianstatic int
2683234862Sadrianargemdio_probe(device_t dev)
2684234862Sadrian{
2685234862Sadrian	device_set_desc(dev, "Atheros AR71xx built-in ethernet interface, MDIO controller");
2686234862Sadrian	return (0);
2687234862Sadrian}
2688234862Sadrian
2689234862Sadrianstatic int
2690234862Sadrianargemdio_attach(device_t dev)
2691234862Sadrian{
2692234862Sadrian	struct arge_softc	*sc;
2693234862Sadrian	int			error = 0;
2694234862Sadrian
2695234862Sadrian	sc = device_get_softc(dev);
2696234862Sadrian	sc->arge_dev = dev;
2697234862Sadrian	sc->arge_mac_unit = device_get_unit(dev);
2698234862Sadrian	sc->arge_rid = 0;
2699234862Sadrian	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
2700234862Sadrian	    &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE);
2701234862Sadrian	if (sc->arge_res == NULL) {
2702234862Sadrian		device_printf(dev, "couldn't map memory\n");
2703234862Sadrian		error = ENXIO;
2704234862Sadrian		goto fail;
2705234862Sadrian	}
2706234862Sadrian
2707234862Sadrian	/* Reset MAC - required for AR71xx MDIO to successfully occur */
2708234862Sadrian	arge_reset_mac(sc);
2709234862Sadrian	/* Reset MII bus */
2710234862Sadrian	arge_reset_miibus(sc);
2711234862Sadrian
2712234862Sadrian	bus_generic_probe(dev);
2713234862Sadrian	bus_enumerate_hinted_children(dev);
2714234862Sadrian	error = bus_generic_attach(dev);
2715234862Sadrianfail:
2716234862Sadrian	return (error);
2717234862Sadrian}
2718234862Sadrian
2719234862Sadrianstatic int
2720234862Sadrianargemdio_detach(device_t dev)
2721234862Sadrian{
2722234862Sadrian	return (0);
2723234862Sadrian}
2724234862Sadrian
2725234862Sadrian#endif
2726