xref: /openbsd/sys/dev/ic/dwqe.c (revision 4fa84378)
1*4fa84378Skettenis /*	$OpenBSD: dwqe.c,v 1.2 2023/02/15 14:10:58 kettenis Exp $	*/
2305ac5f9Spatrick /*
3305ac5f9Spatrick  * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
4305ac5f9Spatrick  * Copyright (c) 2017, 2022 Patrick Wildt <patrick@blueri.se>
5305ac5f9Spatrick  *
6305ac5f9Spatrick  * Permission to use, copy, modify, and distribute this software for any
7305ac5f9Spatrick  * purpose with or without fee is hereby granted, provided that the above
8305ac5f9Spatrick  * copyright notice and this permission notice appear in all copies.
9305ac5f9Spatrick  *
10305ac5f9Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11305ac5f9Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12305ac5f9Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13305ac5f9Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14305ac5f9Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15305ac5f9Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16305ac5f9Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17305ac5f9Spatrick  */
18305ac5f9Spatrick 
19305ac5f9Spatrick /*
20305ac5f9Spatrick  * Driver for the Synopsys Designware ethernet controller.
21305ac5f9Spatrick  */
22305ac5f9Spatrick 
23305ac5f9Spatrick #include "bpfilter.h"
24305ac5f9Spatrick 
25305ac5f9Spatrick #include <sys/param.h>
26305ac5f9Spatrick #include <sys/systm.h>
27305ac5f9Spatrick #include <sys/device.h>
28305ac5f9Spatrick #include <sys/kernel.h>
29305ac5f9Spatrick #include <sys/malloc.h>
30305ac5f9Spatrick #include <sys/mbuf.h>
31305ac5f9Spatrick #include <sys/queue.h>
32305ac5f9Spatrick #include <sys/socket.h>
33305ac5f9Spatrick #include <sys/sockio.h>
34305ac5f9Spatrick #include <sys/timeout.h>
35305ac5f9Spatrick 
36305ac5f9Spatrick #include <machine/bus.h>
37305ac5f9Spatrick #include <machine/fdt.h>
38305ac5f9Spatrick 
39305ac5f9Spatrick #include <net/if.h>
40305ac5f9Spatrick #include <net/if_media.h>
41305ac5f9Spatrick 
42305ac5f9Spatrick #include <dev/ofw/openfirm.h>
43305ac5f9Spatrick #include <dev/ofw/ofw_clock.h>
44305ac5f9Spatrick #include <dev/ofw/ofw_gpio.h>
45305ac5f9Spatrick #include <dev/ofw/ofw_misc.h>
46305ac5f9Spatrick #include <dev/ofw/ofw_pinctrl.h>
47305ac5f9Spatrick #include <dev/ofw/ofw_regulator.h>
48305ac5f9Spatrick #include <dev/ofw/fdt.h>
49305ac5f9Spatrick 
50305ac5f9Spatrick #include <dev/mii/mii.h>
51305ac5f9Spatrick #include <dev/mii/miivar.h>
52305ac5f9Spatrick 
53305ac5f9Spatrick #if NBPFILTER > 0
54305ac5f9Spatrick #include <net/bpf.h>
55305ac5f9Spatrick #endif
56305ac5f9Spatrick 
57305ac5f9Spatrick #include <netinet/in.h>
58305ac5f9Spatrick #include <netinet/if_ether.h>
59305ac5f9Spatrick 
60305ac5f9Spatrick #include <dev/ic/dwqevar.h>
61305ac5f9Spatrick #include <dev/ic/dwqereg.h>
62305ac5f9Spatrick 
63305ac5f9Spatrick struct cfdriver dwqe_cd = {
64305ac5f9Spatrick 	NULL, "dwqe", DV_IFNET
65305ac5f9Spatrick };
66305ac5f9Spatrick 
67305ac5f9Spatrick uint32_t dwqe_read(struct dwqe_softc *, bus_addr_t);
68305ac5f9Spatrick void	dwqe_write(struct dwqe_softc *, bus_addr_t, uint32_t);
69305ac5f9Spatrick 
70305ac5f9Spatrick int	dwqe_ioctl(struct ifnet *, u_long, caddr_t);
71305ac5f9Spatrick void	dwqe_start(struct ifqueue *);
72305ac5f9Spatrick void	dwqe_watchdog(struct ifnet *);
73305ac5f9Spatrick 
74305ac5f9Spatrick int	dwqe_media_change(struct ifnet *);
75305ac5f9Spatrick void	dwqe_media_status(struct ifnet *, struct ifmediareq *);
76305ac5f9Spatrick 
77305ac5f9Spatrick int	dwqe_mii_readreg(struct device *, int, int);
78305ac5f9Spatrick void	dwqe_mii_writereg(struct device *, int, int, int);
79305ac5f9Spatrick void	dwqe_mii_statchg(struct device *);
80305ac5f9Spatrick 
81305ac5f9Spatrick void	dwqe_lladdr_read(struct dwqe_softc *, uint8_t *);
82305ac5f9Spatrick void	dwqe_lladdr_write(struct dwqe_softc *);
83305ac5f9Spatrick 
84305ac5f9Spatrick void	dwqe_tick(void *);
85305ac5f9Spatrick void	dwqe_rxtick(void *);
86305ac5f9Spatrick 
87305ac5f9Spatrick int	dwqe_intr(void *);
88305ac5f9Spatrick void	dwqe_tx_proc(struct dwqe_softc *);
89305ac5f9Spatrick void	dwqe_rx_proc(struct dwqe_softc *);
90305ac5f9Spatrick 
91305ac5f9Spatrick void	dwqe_up(struct dwqe_softc *);
92305ac5f9Spatrick void	dwqe_down(struct dwqe_softc *);
93305ac5f9Spatrick void	dwqe_iff(struct dwqe_softc *);
94305ac5f9Spatrick int	dwqe_encap(struct dwqe_softc *, struct mbuf *, int *, int *);
95305ac5f9Spatrick 
96305ac5f9Spatrick void	dwqe_reset(struct dwqe_softc *);
97305ac5f9Spatrick 
98305ac5f9Spatrick struct dwqe_dmamem *
99305ac5f9Spatrick 	dwqe_dmamem_alloc(struct dwqe_softc *, bus_size_t, bus_size_t);
100305ac5f9Spatrick void	dwqe_dmamem_free(struct dwqe_softc *, struct dwqe_dmamem *);
101305ac5f9Spatrick struct mbuf *dwqe_alloc_mbuf(struct dwqe_softc *, bus_dmamap_t);
102305ac5f9Spatrick void	dwqe_fill_rx_ring(struct dwqe_softc *);
103305ac5f9Spatrick 
104305ac5f9Spatrick int
105305ac5f9Spatrick dwqe_attach(struct dwqe_softc *sc)
106305ac5f9Spatrick {
107305ac5f9Spatrick 	struct ifnet *ifp;
108305ac5f9Spatrick 	uint32_t version, mode;
109305ac5f9Spatrick 	int i;
110305ac5f9Spatrick 
111305ac5f9Spatrick 	version = dwqe_read(sc, GMAC_VERSION);
112*4fa84378Skettenis 	printf(": rev 0x%02x, address %s\n", version & GMAC_VERSION_SNPS_MASK,
113305ac5f9Spatrick 	    ether_sprintf(sc->sc_lladdr));
114305ac5f9Spatrick 
115305ac5f9Spatrick 	for (i = 0; i < 4; i++)
116305ac5f9Spatrick 		sc->sc_hw_feature[i] = dwqe_read(sc, GMAC_MAC_HW_FEATURE(i));
117305ac5f9Spatrick 
118305ac5f9Spatrick 	timeout_set(&sc->sc_tick, dwqe_tick, sc);
119305ac5f9Spatrick 	timeout_set(&sc->sc_rxto, dwqe_rxtick, sc);
120305ac5f9Spatrick 
121305ac5f9Spatrick 	ifp = &sc->sc_ac.ac_if;
122305ac5f9Spatrick 	ifp->if_softc = sc;
123305ac5f9Spatrick 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
124305ac5f9Spatrick 	ifp->if_xflags = IFXF_MPSAFE;
125305ac5f9Spatrick 	ifp->if_ioctl = dwqe_ioctl;
126305ac5f9Spatrick 	ifp->if_qstart = dwqe_start;
127305ac5f9Spatrick 	ifp->if_watchdog = dwqe_watchdog;
128305ac5f9Spatrick 	ifq_set_maxlen(&ifp->if_snd, DWQE_NTXDESC - 1);
129305ac5f9Spatrick 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
130305ac5f9Spatrick 
131305ac5f9Spatrick 	ifp->if_capabilities = IFCAP_VLAN_MTU;
132305ac5f9Spatrick 
133305ac5f9Spatrick 	sc->sc_mii.mii_ifp = ifp;
134305ac5f9Spatrick 	sc->sc_mii.mii_readreg = dwqe_mii_readreg;
135305ac5f9Spatrick 	sc->sc_mii.mii_writereg = dwqe_mii_writereg;
136305ac5f9Spatrick 	sc->sc_mii.mii_statchg = dwqe_mii_statchg;
137305ac5f9Spatrick 
138305ac5f9Spatrick 	ifmedia_init(&sc->sc_media, 0, dwqe_media_change, dwqe_media_status);
139305ac5f9Spatrick 
140305ac5f9Spatrick 	dwqe_reset(sc);
141305ac5f9Spatrick 
142305ac5f9Spatrick 	/* Configure DMA engine. */
143305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_SYS_BUS_MODE);
144305ac5f9Spatrick 	if (sc->sc_fixed_burst)
145305ac5f9Spatrick 		mode |= GMAC_SYS_BUS_MODE_FB;
146305ac5f9Spatrick 	if (sc->sc_mixed_burst)
147305ac5f9Spatrick 		mode |= GMAC_SYS_BUS_MODE_MB;
148305ac5f9Spatrick 	if (sc->sc_aal)
149305ac5f9Spatrick 		mode |= GMAC_SYS_BUS_MODE_AAL;
150305ac5f9Spatrick 	dwqe_write(sc, GMAC_SYS_BUS_MODE, mode);
151305ac5f9Spatrick 
152305ac5f9Spatrick 	/* Configure channel 0. */
153305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_CHAN_CONTROL(0));
154305ac5f9Spatrick 	if (sc->sc_8xpbl)
155305ac5f9Spatrick 		mode |= GMAC_CHAN_CONTROL_8XPBL;
156305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_CONTROL(0), mode);
157305ac5f9Spatrick 
158305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0));
159305ac5f9Spatrick 	mode &= ~GMAC_CHAN_TX_CONTROL_PBL_MASK;
160305ac5f9Spatrick 	mode |= sc->sc_txpbl << GMAC_CHAN_TX_CONTROL_PBL_SHIFT;
161305ac5f9Spatrick 	mode |= GMAC_CHAN_TX_CONTROL_OSP;
162305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), mode);
163305ac5f9Spatrick 	mode &= ~GMAC_CHAN_RX_CONTROL_RPBL_MASK;
164305ac5f9Spatrick 	mode |= sc->sc_rxpbl << GMAC_CHAN_RX_CONTROL_RPBL_SHIFT;
165305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0));
166305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), mode);
167305ac5f9Spatrick 
168305ac5f9Spatrick 	/* Configure AXI master. */
169305ac5f9Spatrick 	if (sc->sc_axi_config) {
170305ac5f9Spatrick 		int i;
171305ac5f9Spatrick 
172305ac5f9Spatrick 		mode = dwqe_read(sc, GMAC_SYS_BUS_MODE);
173305ac5f9Spatrick 
174305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_EN_LPI;
175305ac5f9Spatrick 		if (sc->sc_lpi_en)
176305ac5f9Spatrick 			mode |= GMAC_SYS_BUS_MODE_EN_LPI;
177305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_LPI_XIT_FRM;
178305ac5f9Spatrick 		if (sc->sc_xit_frm)
179305ac5f9Spatrick 			mode |= GMAC_SYS_BUS_MODE_LPI_XIT_FRM;
180305ac5f9Spatrick 
181305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_WR_OSR_LMT_MASK;
182305ac5f9Spatrick 		mode |= (sc->sc_wr_osr_lmt << GMAC_SYS_BUS_MODE_WR_OSR_LMT_SHIFT);
183305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_RD_OSR_LMT_MASK;
184305ac5f9Spatrick 		mode |= (sc->sc_rd_osr_lmt << GMAC_SYS_BUS_MODE_RD_OSR_LMT_SHIFT);
185305ac5f9Spatrick 
186305ac5f9Spatrick 		for (i = 0; i < nitems(sc->sc_blen); i++) {
187305ac5f9Spatrick 			switch (sc->sc_blen[i]) {
188305ac5f9Spatrick 			case 256:
189305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_256;
190305ac5f9Spatrick 				break;
191305ac5f9Spatrick 			case 128:
192305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_128;
193305ac5f9Spatrick 				break;
194305ac5f9Spatrick 			case 64:
195305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_64;
196305ac5f9Spatrick 				break;
197305ac5f9Spatrick 			case 32:
198305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_32;
199305ac5f9Spatrick 				break;
200305ac5f9Spatrick 			case 16:
201305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_16;
202305ac5f9Spatrick 				break;
203305ac5f9Spatrick 			case 8:
204305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_8;
205305ac5f9Spatrick 				break;
206305ac5f9Spatrick 			case 4:
207305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_4;
208305ac5f9Spatrick 				break;
209305ac5f9Spatrick 			}
210305ac5f9Spatrick 		}
211305ac5f9Spatrick 
212305ac5f9Spatrick 		dwqe_write(sc, GMAC_SYS_BUS_MODE, mode);
213305ac5f9Spatrick 	}
214305ac5f9Spatrick 
215305ac5f9Spatrick 	mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, sc->sc_phyloc,
216305ac5f9Spatrick 	    (sc->sc_phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY, 0);
217305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
218305ac5f9Spatrick 		printf("%s: no PHY found!\n", sc->sc_dev.dv_xname);
219305ac5f9Spatrick 		ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
220305ac5f9Spatrick 		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
221305ac5f9Spatrick 	} else
222305ac5f9Spatrick 		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
223305ac5f9Spatrick 
224305ac5f9Spatrick 	if_attach(ifp);
225305ac5f9Spatrick 	ether_ifattach(ifp);
226305ac5f9Spatrick 
227305ac5f9Spatrick 	/* Disable interrupts. */
228305ac5f9Spatrick 	dwqe_write(sc, GMAC_INT_EN, 0);
229305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0);
230305ac5f9Spatrick 
231305ac5f9Spatrick 	return 0;
232305ac5f9Spatrick }
233305ac5f9Spatrick 
234305ac5f9Spatrick uint32_t
235305ac5f9Spatrick dwqe_read(struct dwqe_softc *sc, bus_addr_t addr)
236305ac5f9Spatrick {
237305ac5f9Spatrick 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr);
238305ac5f9Spatrick }
239305ac5f9Spatrick 
240305ac5f9Spatrick void
241305ac5f9Spatrick dwqe_write(struct dwqe_softc *sc, bus_addr_t addr, uint32_t data)
242305ac5f9Spatrick {
243305ac5f9Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, data);
244305ac5f9Spatrick }
245305ac5f9Spatrick 
246305ac5f9Spatrick void
247305ac5f9Spatrick dwqe_lladdr_read(struct dwqe_softc *sc, uint8_t *lladdr)
248305ac5f9Spatrick {
249305ac5f9Spatrick 	uint32_t machi, maclo;
250305ac5f9Spatrick 
251305ac5f9Spatrick 	machi = dwqe_read(sc, GMAC_MAC_ADDR0_HI);
252305ac5f9Spatrick 	maclo = dwqe_read(sc, GMAC_MAC_ADDR0_LO);
253305ac5f9Spatrick 
254305ac5f9Spatrick 	if (machi || maclo) {
255305ac5f9Spatrick 		lladdr[0] = (maclo >> 0) & 0xff;
256305ac5f9Spatrick 		lladdr[1] = (maclo >> 8) & 0xff;
257305ac5f9Spatrick 		lladdr[2] = (maclo >> 16) & 0xff;
258305ac5f9Spatrick 		lladdr[3] = (maclo >> 24) & 0xff;
259305ac5f9Spatrick 		lladdr[4] = (machi >> 0) & 0xff;
260305ac5f9Spatrick 		lladdr[5] = (machi >> 8) & 0xff;
261305ac5f9Spatrick 	} else {
262305ac5f9Spatrick 		ether_fakeaddr(&sc->sc_ac.ac_if);
263305ac5f9Spatrick 	}
264305ac5f9Spatrick }
265305ac5f9Spatrick 
266305ac5f9Spatrick void
267305ac5f9Spatrick dwqe_lladdr_write(struct dwqe_softc *sc)
268305ac5f9Spatrick {
269305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_ADDR0_HI,
270305ac5f9Spatrick 	    sc->sc_lladdr[5] << 8 | sc->sc_lladdr[4] << 0);
271305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_ADDR0_LO,
272305ac5f9Spatrick 	    sc->sc_lladdr[3] << 24 | sc->sc_lladdr[2] << 16 |
273305ac5f9Spatrick 	    sc->sc_lladdr[1] << 8 | sc->sc_lladdr[0] << 0);
274305ac5f9Spatrick }
275305ac5f9Spatrick 
276305ac5f9Spatrick void
277305ac5f9Spatrick dwqe_start(struct ifqueue *ifq)
278305ac5f9Spatrick {
279305ac5f9Spatrick 	struct ifnet *ifp = ifq->ifq_if;
280305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
281305ac5f9Spatrick 	struct mbuf *m;
282305ac5f9Spatrick 	int error, idx, left, used;
283305ac5f9Spatrick 
284305ac5f9Spatrick 	if (!(ifp->if_flags & IFF_RUNNING))
285305ac5f9Spatrick 		return;
286305ac5f9Spatrick 	if (ifq_is_oactive(&ifp->if_snd))
287305ac5f9Spatrick 		return;
288305ac5f9Spatrick 	if (ifq_empty(&ifp->if_snd))
289305ac5f9Spatrick 		return;
290305ac5f9Spatrick 	if (!sc->sc_link)
291305ac5f9Spatrick 		return;
292305ac5f9Spatrick 
293305ac5f9Spatrick 	idx = sc->sc_tx_prod;
294305ac5f9Spatrick 	left = sc->sc_tx_cons;
295305ac5f9Spatrick 	if (left <= idx)
296305ac5f9Spatrick 		left += DWQE_NTXDESC;
297305ac5f9Spatrick 	left -= idx;
298305ac5f9Spatrick 	used = 0;
299305ac5f9Spatrick 
300305ac5f9Spatrick 	for (;;) {
301305ac5f9Spatrick 		if (used + DWQE_NTXSEGS + 1 > left) {
302305ac5f9Spatrick 			ifq_set_oactive(ifq);
303305ac5f9Spatrick 			break;
304305ac5f9Spatrick 		}
305305ac5f9Spatrick 
306305ac5f9Spatrick 		m = ifq_dequeue(ifq);
307305ac5f9Spatrick 		if (m == NULL)
308305ac5f9Spatrick 			break;
309305ac5f9Spatrick 
310305ac5f9Spatrick 		error = dwqe_encap(sc, m, &idx, &used);
311305ac5f9Spatrick 		if (error == EFBIG) {
312305ac5f9Spatrick 			m_freem(m); /* give up: drop it */
313305ac5f9Spatrick 			ifp->if_oerrors++;
314305ac5f9Spatrick 			continue;
315305ac5f9Spatrick 		}
316305ac5f9Spatrick 
317305ac5f9Spatrick #if NBPFILTER > 0
318305ac5f9Spatrick 		if (ifp->if_bpf)
319305ac5f9Spatrick 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
320305ac5f9Spatrick #endif
321305ac5f9Spatrick 	}
322305ac5f9Spatrick 
323305ac5f9Spatrick 	if (sc->sc_tx_prod != idx) {
324305ac5f9Spatrick 		sc->sc_tx_prod = idx;
325305ac5f9Spatrick 
326305ac5f9Spatrick 		/* Set a timeout in case the chip goes out to lunch. */
327305ac5f9Spatrick 		ifp->if_timer = 5;
328305ac5f9Spatrick 	}
329305ac5f9Spatrick }
330305ac5f9Spatrick 
331305ac5f9Spatrick int
332305ac5f9Spatrick dwqe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
333305ac5f9Spatrick {
334305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
335305ac5f9Spatrick 	struct ifreq *ifr = (struct ifreq *)addr;
336305ac5f9Spatrick 	int error = 0, s;
337305ac5f9Spatrick 
338305ac5f9Spatrick 	s = splnet();
339305ac5f9Spatrick 
340305ac5f9Spatrick 	switch (cmd) {
341305ac5f9Spatrick 	case SIOCSIFADDR:
342305ac5f9Spatrick 		ifp->if_flags |= IFF_UP;
343305ac5f9Spatrick 		/* FALLTHROUGH */
344305ac5f9Spatrick 	case SIOCSIFFLAGS:
345305ac5f9Spatrick 		if (ifp->if_flags & IFF_UP) {
346305ac5f9Spatrick 			if (ifp->if_flags & IFF_RUNNING)
347305ac5f9Spatrick 				error = ENETRESET;
348305ac5f9Spatrick 			else
349305ac5f9Spatrick 				dwqe_up(sc);
350305ac5f9Spatrick 		} else {
351305ac5f9Spatrick 			if (ifp->if_flags & IFF_RUNNING)
352305ac5f9Spatrick 				dwqe_down(sc);
353305ac5f9Spatrick 		}
354305ac5f9Spatrick 		break;
355305ac5f9Spatrick 
356305ac5f9Spatrick 	case SIOCGIFMEDIA:
357305ac5f9Spatrick 	case SIOCSIFMEDIA:
358305ac5f9Spatrick 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
359305ac5f9Spatrick 		break;
360305ac5f9Spatrick 
361305ac5f9Spatrick 	case SIOCGIFRXR:
362305ac5f9Spatrick 		error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data,
363305ac5f9Spatrick 		    NULL, MCLBYTES, &sc->sc_rx_ring);
364305ac5f9Spatrick 		break;
365305ac5f9Spatrick 
366305ac5f9Spatrick 	default:
367305ac5f9Spatrick 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr);
368305ac5f9Spatrick 		break;
369305ac5f9Spatrick 	}
370305ac5f9Spatrick 
371305ac5f9Spatrick 	if (error == ENETRESET) {
372305ac5f9Spatrick 		if (ifp->if_flags & IFF_RUNNING)
373305ac5f9Spatrick 			dwqe_iff(sc);
374305ac5f9Spatrick 		error = 0;
375305ac5f9Spatrick 	}
376305ac5f9Spatrick 
377305ac5f9Spatrick 	splx(s);
378305ac5f9Spatrick 	return (error);
379305ac5f9Spatrick }
380305ac5f9Spatrick 
381305ac5f9Spatrick void
382305ac5f9Spatrick dwqe_watchdog(struct ifnet *ifp)
383305ac5f9Spatrick {
384305ac5f9Spatrick 	printf("%s\n", __func__);
385305ac5f9Spatrick }
386305ac5f9Spatrick 
387305ac5f9Spatrick int
388305ac5f9Spatrick dwqe_media_change(struct ifnet *ifp)
389305ac5f9Spatrick {
390305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
391305ac5f9Spatrick 
392305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
393305ac5f9Spatrick 		mii_mediachg(&sc->sc_mii);
394305ac5f9Spatrick 
395305ac5f9Spatrick 	return (0);
396305ac5f9Spatrick }
397305ac5f9Spatrick 
398305ac5f9Spatrick void
399305ac5f9Spatrick dwqe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
400305ac5f9Spatrick {
401305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
402305ac5f9Spatrick 
403305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
404305ac5f9Spatrick 		mii_pollstat(&sc->sc_mii);
405305ac5f9Spatrick 		ifmr->ifm_active = sc->sc_mii.mii_media_active;
406305ac5f9Spatrick 		ifmr->ifm_status = sc->sc_mii.mii_media_status;
407305ac5f9Spatrick 	}
408305ac5f9Spatrick }
409305ac5f9Spatrick 
410305ac5f9Spatrick int
411305ac5f9Spatrick dwqe_mii_readreg(struct device *self, int phy, int reg)
412305ac5f9Spatrick {
413305ac5f9Spatrick 	struct dwqe_softc *sc = (void *)self;
414305ac5f9Spatrick 	int n;
415305ac5f9Spatrick 
416305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_MDIO_ADDR,
417305ac5f9Spatrick 	    sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT |
418305ac5f9Spatrick 	    (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) |
419305ac5f9Spatrick 	    (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) |
420305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GOC_READ |
421305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GB);
422305ac5f9Spatrick 	delay(10000);
423305ac5f9Spatrick 
424305ac5f9Spatrick 	for (n = 0; n < 1000; n++) {
425305ac5f9Spatrick 		if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0)
426305ac5f9Spatrick 			return dwqe_read(sc, GMAC_MAC_MDIO_DATA);
427305ac5f9Spatrick 		delay(10);
428305ac5f9Spatrick 	}
429305ac5f9Spatrick 
430305ac5f9Spatrick 	printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname);
431305ac5f9Spatrick 	return (0);
432305ac5f9Spatrick }
433305ac5f9Spatrick 
434305ac5f9Spatrick void
435305ac5f9Spatrick dwqe_mii_writereg(struct device *self, int phy, int reg, int val)
436305ac5f9Spatrick {
437305ac5f9Spatrick 	struct dwqe_softc *sc = (void *)self;
438305ac5f9Spatrick 	int n;
439305ac5f9Spatrick 
440305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_MDIO_DATA, val);
441305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_MDIO_ADDR,
442305ac5f9Spatrick 	    sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT |
443305ac5f9Spatrick 	    (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) |
444305ac5f9Spatrick 	    (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) |
445305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GOC_WRITE |
446305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GB);
447305ac5f9Spatrick 	delay(10000);
448305ac5f9Spatrick 	for (n = 0; n < 1000; n++) {
449305ac5f9Spatrick 		if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0)
450305ac5f9Spatrick 			return;
451305ac5f9Spatrick 		delay(10);
452305ac5f9Spatrick 	}
453305ac5f9Spatrick 
454305ac5f9Spatrick 	printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname);
455305ac5f9Spatrick }
456305ac5f9Spatrick 
457305ac5f9Spatrick void
458305ac5f9Spatrick dwqe_mii_statchg(struct device *self)
459305ac5f9Spatrick {
460305ac5f9Spatrick 	struct dwqe_softc *sc = (void *)self;
461305ac5f9Spatrick 	uint32_t conf;
462305ac5f9Spatrick 
463305ac5f9Spatrick 	conf = dwqe_read(sc, GMAC_MAC_CONF);
464305ac5f9Spatrick 	conf &= ~(GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES);
465305ac5f9Spatrick 
466305ac5f9Spatrick 	switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
467305ac5f9Spatrick 	case IFM_1000_SX:
468305ac5f9Spatrick 	case IFM_1000_LX:
469305ac5f9Spatrick 	case IFM_1000_CX:
470305ac5f9Spatrick 	case IFM_1000_T:
471305ac5f9Spatrick 		sc->sc_link = 1;
472305ac5f9Spatrick 		break;
473305ac5f9Spatrick 	case IFM_100_TX:
474305ac5f9Spatrick 		conf |= GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES;
475305ac5f9Spatrick 		sc->sc_link = 1;
476305ac5f9Spatrick 		break;
477305ac5f9Spatrick 	case IFM_10_T:
478305ac5f9Spatrick 		conf |= GMAC_MAC_CONF_PS;
479305ac5f9Spatrick 		sc->sc_link = 1;
480305ac5f9Spatrick 		break;
481305ac5f9Spatrick 	default:
482305ac5f9Spatrick 		sc->sc_link = 0;
483305ac5f9Spatrick 		return;
484305ac5f9Spatrick 	}
485305ac5f9Spatrick 
486305ac5f9Spatrick 	if (sc->sc_link == 0)
487305ac5f9Spatrick 		return;
488305ac5f9Spatrick 
489305ac5f9Spatrick 	conf &= ~GMAC_MAC_CONF_DM;
490305ac5f9Spatrick 	if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
491305ac5f9Spatrick 		conf |= GMAC_MAC_CONF_DM;
492305ac5f9Spatrick 
493305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, conf);
494305ac5f9Spatrick }
495305ac5f9Spatrick 
496305ac5f9Spatrick void
497305ac5f9Spatrick dwqe_tick(void *arg)
498305ac5f9Spatrick {
499305ac5f9Spatrick 	struct dwqe_softc *sc = arg;
500305ac5f9Spatrick 	int s;
501305ac5f9Spatrick 
502305ac5f9Spatrick 	s = splnet();
503305ac5f9Spatrick 	mii_tick(&sc->sc_mii);
504305ac5f9Spatrick 	splx(s);
505305ac5f9Spatrick 
506305ac5f9Spatrick 	timeout_add_sec(&sc->sc_tick, 1);
507305ac5f9Spatrick }
508305ac5f9Spatrick 
509305ac5f9Spatrick void
510305ac5f9Spatrick dwqe_rxtick(void *arg)
511305ac5f9Spatrick {
512305ac5f9Spatrick 	struct dwqe_softc *sc = arg;
513305ac5f9Spatrick 	int s;
514305ac5f9Spatrick 
515305ac5f9Spatrick 	s = splnet();
516305ac5f9Spatrick 
517305ac5f9Spatrick 	/* TODO: disable RXQ? */
518305ac5f9Spatrick 	printf("%s:%d\n", __func__, __LINE__);
519305ac5f9Spatrick 
520305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring),
521305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_rxring),
522305ac5f9Spatrick 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
523305ac5f9Spatrick 
524305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), 0);
525305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), 0);
526305ac5f9Spatrick 
527305ac5f9Spatrick 	sc->sc_rx_prod = sc->sc_rx_cons = 0;
528305ac5f9Spatrick 	dwqe_fill_rx_ring(sc);
529305ac5f9Spatrick 
530305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring),
531305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_rxring),
532305ac5f9Spatrick 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
533305ac5f9Spatrick 
534305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32);
535305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring));
536305ac5f9Spatrick 
537305ac5f9Spatrick 	/* TODO: re-enable RXQ? */
538305ac5f9Spatrick 
539305ac5f9Spatrick 	splx(s);
540305ac5f9Spatrick }
541305ac5f9Spatrick 
542305ac5f9Spatrick int
543305ac5f9Spatrick dwqe_intr(void *arg)
544305ac5f9Spatrick {
545305ac5f9Spatrick 	struct dwqe_softc *sc = arg;
546305ac5f9Spatrick 	uint32_t reg;
547305ac5f9Spatrick 
548305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_INT_STATUS);
549305ac5f9Spatrick 	dwqe_write(sc, GMAC_INT_STATUS, reg);
550305ac5f9Spatrick 
551305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_STATUS(0));
552305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_STATUS(0), reg);
553305ac5f9Spatrick 
554305ac5f9Spatrick 	if (reg & GMAC_CHAN_STATUS_RI)
555305ac5f9Spatrick 		dwqe_rx_proc(sc);
556305ac5f9Spatrick 
557305ac5f9Spatrick 	if (reg & GMAC_CHAN_STATUS_TI)
558305ac5f9Spatrick 		dwqe_tx_proc(sc);
559305ac5f9Spatrick 
560305ac5f9Spatrick 	return (1);
561305ac5f9Spatrick }
562305ac5f9Spatrick 
563305ac5f9Spatrick void
564305ac5f9Spatrick dwqe_tx_proc(struct dwqe_softc *sc)
565305ac5f9Spatrick {
566305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
567305ac5f9Spatrick 	struct dwqe_desc *txd;
568305ac5f9Spatrick 	struct dwqe_buf *txb;
569305ac5f9Spatrick 	int idx, txfree;
570305ac5f9Spatrick 
571305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 0,
572305ac5f9Spatrick 	    DWQE_DMA_LEN(sc->sc_txring),
573305ac5f9Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
574305ac5f9Spatrick 
575305ac5f9Spatrick 	txfree = 0;
576305ac5f9Spatrick 	while (sc->sc_tx_cons != sc->sc_tx_prod) {
577305ac5f9Spatrick 		idx = sc->sc_tx_cons;
578305ac5f9Spatrick 		KASSERT(idx < DWQE_NTXDESC);
579305ac5f9Spatrick 
580305ac5f9Spatrick 		txd = &sc->sc_txdesc[idx];
581305ac5f9Spatrick 		if (txd->sd_tdes3 & TDES3_OWN)
582305ac5f9Spatrick 			break;
583305ac5f9Spatrick 
584305ac5f9Spatrick 		txb = &sc->sc_txbuf[idx];
585305ac5f9Spatrick 		if (txb->tb_m) {
586305ac5f9Spatrick 			bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0,
587305ac5f9Spatrick 			    txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
588305ac5f9Spatrick 			bus_dmamap_unload(sc->sc_dmat, txb->tb_map);
589305ac5f9Spatrick 
590305ac5f9Spatrick 			m_freem(txb->tb_m);
591305ac5f9Spatrick 			txb->tb_m = NULL;
592305ac5f9Spatrick 		}
593305ac5f9Spatrick 
594305ac5f9Spatrick 		txfree++;
595305ac5f9Spatrick 
596305ac5f9Spatrick 		if (sc->sc_tx_cons == (DWQE_NTXDESC - 1))
597305ac5f9Spatrick 			sc->sc_tx_cons = 0;
598305ac5f9Spatrick 		else
599305ac5f9Spatrick 			sc->sc_tx_cons++;
600305ac5f9Spatrick 
601305ac5f9Spatrick 		txd->sd_tdes3 = 0;
602305ac5f9Spatrick 	}
603305ac5f9Spatrick 
604305ac5f9Spatrick 	if (sc->sc_tx_cons == sc->sc_tx_prod)
605305ac5f9Spatrick 		ifp->if_timer = 0;
606305ac5f9Spatrick 
607305ac5f9Spatrick 	if (txfree) {
608305ac5f9Spatrick 		if (ifq_is_oactive(&ifp->if_snd))
609305ac5f9Spatrick 			ifq_restart(&ifp->if_snd);
610305ac5f9Spatrick 	}
611305ac5f9Spatrick }
612305ac5f9Spatrick 
613305ac5f9Spatrick void
614305ac5f9Spatrick dwqe_rx_proc(struct dwqe_softc *sc)
615305ac5f9Spatrick {
616305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
617305ac5f9Spatrick 	struct dwqe_desc *rxd;
618305ac5f9Spatrick 	struct dwqe_buf *rxb;
619305ac5f9Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
620305ac5f9Spatrick 	struct mbuf *m;
621305ac5f9Spatrick 	int idx, len, cnt, put;
622305ac5f9Spatrick 
623305ac5f9Spatrick 	if ((ifp->if_flags & IFF_RUNNING) == 0)
624305ac5f9Spatrick 		return;
625305ac5f9Spatrick 
626305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0,
627305ac5f9Spatrick 	    DWQE_DMA_LEN(sc->sc_rxring),
628305ac5f9Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
629305ac5f9Spatrick 
630305ac5f9Spatrick 	cnt = if_rxr_inuse(&sc->sc_rx_ring);
631305ac5f9Spatrick 	put = 0;
632305ac5f9Spatrick 	while (put < cnt) {
633305ac5f9Spatrick 		idx = sc->sc_rx_cons;
634305ac5f9Spatrick 		KASSERT(idx < DWQE_NRXDESC);
635305ac5f9Spatrick 
636305ac5f9Spatrick 		rxd = &sc->sc_rxdesc[idx];
637305ac5f9Spatrick 		if (rxd->sd_tdes3 & RDES3_OWN)
638305ac5f9Spatrick 			break;
639305ac5f9Spatrick 
640305ac5f9Spatrick 		len = rxd->sd_tdes3 & RDES3_LENGTH;
641305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[idx];
642305ac5f9Spatrick 		KASSERT(rxb->tb_m);
643305ac5f9Spatrick 
644305ac5f9Spatrick 		bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0,
645305ac5f9Spatrick 		    len, BUS_DMASYNC_POSTREAD);
646305ac5f9Spatrick 		bus_dmamap_unload(sc->sc_dmat, rxb->tb_map);
647305ac5f9Spatrick 
648305ac5f9Spatrick 		/* Strip off CRC. */
649305ac5f9Spatrick 		len -= ETHER_CRC_LEN;
650305ac5f9Spatrick 		KASSERT(len > 0);
651305ac5f9Spatrick 
652305ac5f9Spatrick 		m = rxb->tb_m;
653305ac5f9Spatrick 		rxb->tb_m = NULL;
654305ac5f9Spatrick 		m->m_pkthdr.len = m->m_len = len;
655305ac5f9Spatrick 
656305ac5f9Spatrick 		ml_enqueue(&ml, m);
657305ac5f9Spatrick 
658305ac5f9Spatrick 		put++;
659305ac5f9Spatrick 		if (sc->sc_rx_cons == (DWQE_NRXDESC - 1))
660305ac5f9Spatrick 			sc->sc_rx_cons = 0;
661305ac5f9Spatrick 		else
662305ac5f9Spatrick 			sc->sc_rx_cons++;
663305ac5f9Spatrick 	}
664305ac5f9Spatrick 
665305ac5f9Spatrick 	if_rxr_put(&sc->sc_rx_ring, put);
666305ac5f9Spatrick 	if (ifiq_input(&ifp->if_rcv, &ml))
667305ac5f9Spatrick 		if_rxr_livelocked(&sc->sc_rx_ring);
668305ac5f9Spatrick 
669305ac5f9Spatrick 	dwqe_fill_rx_ring(sc);
670305ac5f9Spatrick 
671305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0,
672305ac5f9Spatrick 	    DWQE_DMA_LEN(sc->sc_rxring),
673305ac5f9Spatrick 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
674305ac5f9Spatrick 
675305ac5f9Spatrick }
676305ac5f9Spatrick 
677305ac5f9Spatrick void
678305ac5f9Spatrick dwqe_up(struct dwqe_softc *sc)
679305ac5f9Spatrick {
680305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
681305ac5f9Spatrick 	struct dwqe_buf *txb, *rxb;
682305ac5f9Spatrick 	uint32_t mode, reg, tqs, rqs;
683305ac5f9Spatrick 	int i;
684305ac5f9Spatrick 
685305ac5f9Spatrick 	/* Allocate Tx descriptor ring. */
686305ac5f9Spatrick 	sc->sc_txring = dwqe_dmamem_alloc(sc,
687305ac5f9Spatrick 	    DWQE_NTXDESC * sizeof(struct dwqe_desc), 8);
688305ac5f9Spatrick 	sc->sc_txdesc = DWQE_DMA_KVA(sc->sc_txring);
689305ac5f9Spatrick 
690305ac5f9Spatrick 	sc->sc_txbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NTXDESC,
691305ac5f9Spatrick 	    M_DEVBUF, M_WAITOK);
692305ac5f9Spatrick 	for (i = 0; i < DWQE_NTXDESC; i++) {
693305ac5f9Spatrick 		txb = &sc->sc_txbuf[i];
694305ac5f9Spatrick 		bus_dmamap_create(sc->sc_dmat, MCLBYTES, DWQE_NTXSEGS,
695305ac5f9Spatrick 		    MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map);
696305ac5f9Spatrick 		txb->tb_m = NULL;
697305ac5f9Spatrick 	}
698305ac5f9Spatrick 
699305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring),
700305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE);
701305ac5f9Spatrick 
702305ac5f9Spatrick 	sc->sc_tx_prod = sc->sc_tx_cons = 0;
703305ac5f9Spatrick 
704305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_txring) >> 32);
705305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_txring));
706305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_RING_LEN(0), DWQE_NTXDESC - 1);
707305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring));
708305ac5f9Spatrick 
709305ac5f9Spatrick 	/* Allocate  descriptor ring. */
710305ac5f9Spatrick 	sc->sc_rxring = dwqe_dmamem_alloc(sc,
711305ac5f9Spatrick 	    DWQE_NRXDESC * sizeof(struct dwqe_desc), 8);
712305ac5f9Spatrick 	sc->sc_rxdesc = DWQE_DMA_KVA(sc->sc_rxring);
713305ac5f9Spatrick 
714305ac5f9Spatrick 	sc->sc_rxbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NRXDESC,
715305ac5f9Spatrick 	    M_DEVBUF, M_WAITOK);
716305ac5f9Spatrick 
717305ac5f9Spatrick 	for (i = 0; i < DWQE_NRXDESC; i++) {
718305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[i];
719305ac5f9Spatrick 		bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
720305ac5f9Spatrick 		    MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map);
721305ac5f9Spatrick 		rxb->tb_m = NULL;
722305ac5f9Spatrick 	}
723305ac5f9Spatrick 
724305ac5f9Spatrick 	if_rxr_init(&sc->sc_rx_ring, 2, DWQE_NRXDESC);
725305ac5f9Spatrick 
726305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32);
727305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring));
728305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_RING_LEN(0), DWQE_NRXDESC - 1);
729305ac5f9Spatrick 
730305ac5f9Spatrick 	sc->sc_rx_prod = sc->sc_rx_cons = 0;
731305ac5f9Spatrick 	dwqe_fill_rx_ring(sc);
732305ac5f9Spatrick 
733305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring),
734305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_rxring),
735305ac5f9Spatrick 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
736305ac5f9Spatrick 
737305ac5f9Spatrick 	dwqe_lladdr_write(sc);
738305ac5f9Spatrick 
739305ac5f9Spatrick 	/* Configure media. */
740305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
741305ac5f9Spatrick 		mii_mediachg(&sc->sc_mii);
742305ac5f9Spatrick 
743305ac5f9Spatrick 	/* Program promiscuous mode and multicast filters. */
744305ac5f9Spatrick 	dwqe_iff(sc);
745305ac5f9Spatrick 
746305ac5f9Spatrick 	ifp->if_flags |= IFF_RUNNING;
747305ac5f9Spatrick 	ifq_clr_oactive(&ifp->if_snd);
748305ac5f9Spatrick 
749305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_1US_TIC_CTR, (sc->sc_clk / 1000000) - 1);
750305ac5f9Spatrick 
751305ac5f9Spatrick 	/* Start receive DMA */
752305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0));
753305ac5f9Spatrick 	reg |= GMAC_CHAN_RX_CONTROL_SR;
754305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg);
755305ac5f9Spatrick 
756305ac5f9Spatrick 	/* Start transmit DMA */
757305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0));
758305ac5f9Spatrick 	reg |= GMAC_CHAN_TX_CONTROL_ST;
759305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg);
760305ac5f9Spatrick 
761305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_MTL_CHAN_RX_OP_MODE(0));
762305ac5f9Spatrick 	if (sc->sc_force_thresh_dma_mode) {
763305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RSF;
764305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RTC_MASK;
765305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_RX_OP_MODE_RTC_128;
766305ac5f9Spatrick 	} else {
767305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_RX_OP_MODE_RSF;
768305ac5f9Spatrick 	}
769305ac5f9Spatrick 	mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK;
770305ac5f9Spatrick 	rqs = (128 << GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(sc->sc_hw_feature[1]) /
771305ac5f9Spatrick 	    256) - 1;
772305ac5f9Spatrick 	mode |= rqs << GMAC_MTL_CHAN_RX_OP_MODE_RQS_SHIFT;
773305ac5f9Spatrick 	dwqe_write(sc, GMAC_MTL_CHAN_RX_OP_MODE(0), mode);
774305ac5f9Spatrick 
775305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0));
776305ac5f9Spatrick 	if (sc->sc_force_thresh_dma_mode) {
777305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TSF;
778305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TTC_MASK;
779305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_TX_OP_MODE_TTC_128;
780305ac5f9Spatrick 	} else {
781305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_TX_OP_MODE_TSF;
782305ac5f9Spatrick 	}
783305ac5f9Spatrick 	mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TXQEN_MASK;
784305ac5f9Spatrick 	mode |= GMAC_MTL_CHAN_TX_OP_MODE_TXQEN;
785305ac5f9Spatrick 	mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK;
786305ac5f9Spatrick 	tqs = (128 << GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(sc->sc_hw_feature[1]) /
787305ac5f9Spatrick 	    256) - 1;
788305ac5f9Spatrick 	mode |= tqs << GMAC_MTL_CHAN_TX_OP_MODE_TQS_SHIFT;
789305ac5f9Spatrick 	dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), mode);
790305ac5f9Spatrick 
791305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_QX_TX_FLOW_CTRL(0));
792305ac5f9Spatrick 	reg |= 0xffffU << GMAC_QX_TX_FLOW_CTRL_PT_SHIFT;
793305ac5f9Spatrick 	reg |= GMAC_QX_TX_FLOW_CTRL_TFE;
794305ac5f9Spatrick 	dwqe_write(sc, GMAC_QX_TX_FLOW_CTRL(0), reg);
795305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_RX_FLOW_CTRL);
796305ac5f9Spatrick 	reg |= GMAC_RX_FLOW_CTRL_RFE;
797305ac5f9Spatrick 	dwqe_write(sc, GMAC_RX_FLOW_CTRL, reg);
798305ac5f9Spatrick 
799305ac5f9Spatrick 	dwqe_write(sc, GMAC_RXQ_CTRL0, GMAC_RXQ_CTRL0_DCB_QUEUE_EN(0));
800305ac5f9Spatrick 
801305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, dwqe_read(sc, GMAC_MAC_CONF) |
802305ac5f9Spatrick 	    GMAC_MAC_CONF_BE | GMAC_MAC_CONF_JD | GMAC_MAC_CONF_JE |
803305ac5f9Spatrick 	    GMAC_MAC_CONF_DCRS | GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE);
804305ac5f9Spatrick 
805305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_INTR_ENA(0),
806305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_NIE |
807305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_AIE |
808305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_FBE |
809305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_RIE |
810305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_TIE);
811305ac5f9Spatrick 
812305ac5f9Spatrick 	timeout_add_sec(&sc->sc_tick, 1);
813305ac5f9Spatrick }
814305ac5f9Spatrick 
815305ac5f9Spatrick void
816305ac5f9Spatrick dwqe_down(struct dwqe_softc *sc)
817305ac5f9Spatrick {
818305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
819305ac5f9Spatrick 	struct dwqe_buf *txb, *rxb;
820305ac5f9Spatrick 	uint32_t reg;
821305ac5f9Spatrick 	int i;
822305ac5f9Spatrick 
823305ac5f9Spatrick 	timeout_del(&sc->sc_rxto);
824305ac5f9Spatrick 	timeout_del(&sc->sc_tick);
825305ac5f9Spatrick 
826305ac5f9Spatrick 	ifp->if_flags &= ~IFF_RUNNING;
827305ac5f9Spatrick 	ifq_clr_oactive(&ifp->if_snd);
828305ac5f9Spatrick 	ifp->if_timer = 0;
829305ac5f9Spatrick 
830305ac5f9Spatrick 	/* Disable receiver */
831305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_MAC_CONF);
832305ac5f9Spatrick 	reg &= ~GMAC_MAC_CONF_RE;
833305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, reg);
834305ac5f9Spatrick 
835305ac5f9Spatrick 	/* Stop receive DMA */
836305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0));
837305ac5f9Spatrick 	reg &= ~GMAC_CHAN_RX_CONTROL_SR;
838305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg);
839305ac5f9Spatrick 
840305ac5f9Spatrick 	/* Stop transmit DMA */
841305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0));
842305ac5f9Spatrick 	reg &= ~GMAC_CHAN_TX_CONTROL_ST;
843305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg);
844305ac5f9Spatrick 
845305ac5f9Spatrick 	/* Flush data in the TX FIFO */
846305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0));
847305ac5f9Spatrick 	reg |= GMAC_MTL_CHAN_TX_OP_MODE_FTQ;
848305ac5f9Spatrick 	dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), reg);
849305ac5f9Spatrick 	/* Wait for flush to complete */
850305ac5f9Spatrick 	for (i = 10000; i > 0; i--) {
851305ac5f9Spatrick 		reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0));
852305ac5f9Spatrick 		if ((reg & GMAC_MTL_CHAN_TX_OP_MODE_FTQ) == 0)
853305ac5f9Spatrick 			break;
854305ac5f9Spatrick 		delay(1);
855305ac5f9Spatrick 	}
856305ac5f9Spatrick 	if (i == 0) {
857305ac5f9Spatrick 		printf("%s: timeout flushing TX queue\n",
858305ac5f9Spatrick 		    sc->sc_dev.dv_xname);
859305ac5f9Spatrick 	}
860305ac5f9Spatrick 
861305ac5f9Spatrick 	/* Disable transmitter */
862305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_MAC_CONF);
863305ac5f9Spatrick 	reg &= ~GMAC_MAC_CONF_TE;
864305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, reg);
865305ac5f9Spatrick 
866305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0);
867305ac5f9Spatrick 
868305ac5f9Spatrick 	intr_barrier(sc->sc_ih);
869305ac5f9Spatrick 	ifq_barrier(&ifp->if_snd);
870305ac5f9Spatrick 
871305ac5f9Spatrick 	for (i = 0; i < DWQE_NTXDESC; i++) {
872305ac5f9Spatrick 		txb = &sc->sc_txbuf[i];
873305ac5f9Spatrick 		if (txb->tb_m) {
874305ac5f9Spatrick 			bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0,
875305ac5f9Spatrick 			    txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
876305ac5f9Spatrick 			bus_dmamap_unload(sc->sc_dmat, txb->tb_map);
877305ac5f9Spatrick 			m_freem(txb->tb_m);
878305ac5f9Spatrick 		}
879305ac5f9Spatrick 		bus_dmamap_destroy(sc->sc_dmat, txb->tb_map);
880305ac5f9Spatrick 	}
881305ac5f9Spatrick 
882305ac5f9Spatrick 	dwqe_dmamem_free(sc, sc->sc_txring);
883305ac5f9Spatrick 	free(sc->sc_txbuf, M_DEVBUF, 0);
884305ac5f9Spatrick 
885305ac5f9Spatrick 	for (i = 0; i < DWQE_NRXDESC; i++) {
886305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[i];
887305ac5f9Spatrick 		if (rxb->tb_m) {
888305ac5f9Spatrick 			bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0,
889305ac5f9Spatrick 			    rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
890305ac5f9Spatrick 			bus_dmamap_unload(sc->sc_dmat, rxb->tb_map);
891305ac5f9Spatrick 			m_freem(rxb->tb_m);
892305ac5f9Spatrick 		}
893305ac5f9Spatrick 		bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map);
894305ac5f9Spatrick 	}
895305ac5f9Spatrick 
896305ac5f9Spatrick 	dwqe_dmamem_free(sc, sc->sc_rxring);
897305ac5f9Spatrick 	free(sc->sc_rxbuf, M_DEVBUF, 0);
898305ac5f9Spatrick }
899305ac5f9Spatrick 
900305ac5f9Spatrick /* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */
901305ac5f9Spatrick static uint32_t
902305ac5f9Spatrick bitrev32(uint32_t x)
903305ac5f9Spatrick {
904305ac5f9Spatrick 	x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
905305ac5f9Spatrick 	x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
906305ac5f9Spatrick 	x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
907305ac5f9Spatrick 	x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
908305ac5f9Spatrick 
909305ac5f9Spatrick 	return (x >> 16) | (x << 16);
910305ac5f9Spatrick }
911305ac5f9Spatrick 
912305ac5f9Spatrick void
913305ac5f9Spatrick dwqe_iff(struct dwqe_softc *sc)
914305ac5f9Spatrick {
915305ac5f9Spatrick 	struct arpcom *ac = &sc->sc_ac;
916305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
917305ac5f9Spatrick 	struct ether_multi *enm;
918305ac5f9Spatrick 	struct ether_multistep step;
919305ac5f9Spatrick 	uint32_t crc, hash[2], hashbit, hashreg;
920305ac5f9Spatrick 	uint32_t reg;
921305ac5f9Spatrick 
922305ac5f9Spatrick 	reg = 0;
923305ac5f9Spatrick 
924305ac5f9Spatrick 	ifp->if_flags &= ~IFF_ALLMULTI;
925305ac5f9Spatrick 	bzero(hash, sizeof(hash));
926305ac5f9Spatrick 	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
927305ac5f9Spatrick 		ifp->if_flags |= IFF_ALLMULTI;
928305ac5f9Spatrick 		reg |= GMAC_MAC_PACKET_FILTER_PM;
929305ac5f9Spatrick 		if (ifp->if_flags & IFF_PROMISC)
930305ac5f9Spatrick 			reg |= GMAC_MAC_PACKET_FILTER_PR |
931305ac5f9Spatrick 			    GMAC_MAC_PACKET_FILTER_PCF_ALL;
932305ac5f9Spatrick 	} else {
933305ac5f9Spatrick 		reg |= GMAC_MAC_PACKET_FILTER_HMC;
934305ac5f9Spatrick 		ETHER_FIRST_MULTI(step, ac, enm);
935305ac5f9Spatrick 		while (enm != NULL) {
936305ac5f9Spatrick 			crc = ether_crc32_le(enm->enm_addrlo,
937305ac5f9Spatrick 			    ETHER_ADDR_LEN) & 0x7f;
938305ac5f9Spatrick 
939305ac5f9Spatrick 			crc = bitrev32(~crc) >> 26;
940305ac5f9Spatrick 			hashreg = (crc >> 5);
941305ac5f9Spatrick 			hashbit = (crc & 0x1f);
942305ac5f9Spatrick 			hash[hashreg] |= (1 << hashbit);
943305ac5f9Spatrick 
944305ac5f9Spatrick 			ETHER_NEXT_MULTI(step, enm);
945305ac5f9Spatrick 		}
946305ac5f9Spatrick 	}
947305ac5f9Spatrick 
948305ac5f9Spatrick 	dwqe_lladdr_write(sc);
949305ac5f9Spatrick 
950305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_HASH_TAB_REG0, hash[0]);
951305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_HASH_TAB_REG1, hash[1]);
952305ac5f9Spatrick 
953305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_PACKET_FILTER, reg);
954305ac5f9Spatrick }
955305ac5f9Spatrick 
956305ac5f9Spatrick int
957305ac5f9Spatrick dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used)
958305ac5f9Spatrick {
959305ac5f9Spatrick 	struct dwqe_desc *txd, *txd_start;
960305ac5f9Spatrick 	bus_dmamap_t map;
961305ac5f9Spatrick 	int cur, frag, i;
962305ac5f9Spatrick 
963305ac5f9Spatrick 	cur = frag = *idx;
964305ac5f9Spatrick 	map = sc->sc_txbuf[cur].tb_map;
965305ac5f9Spatrick 
966305ac5f9Spatrick 	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) {
967305ac5f9Spatrick 		if (m_defrag(m, M_DONTWAIT))
968305ac5f9Spatrick 			return (EFBIG);
969305ac5f9Spatrick 		if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT))
970305ac5f9Spatrick 			return (EFBIG);
971305ac5f9Spatrick 	}
972305ac5f9Spatrick 
973305ac5f9Spatrick 	/* Sync the DMA map. */
974305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
975305ac5f9Spatrick 	    BUS_DMASYNC_PREWRITE);
976305ac5f9Spatrick 
977305ac5f9Spatrick 	txd = txd_start = &sc->sc_txdesc[frag];
978305ac5f9Spatrick 	for (i = 0; i < map->dm_nsegs; i++) {
979305ac5f9Spatrick 		/* TODO: check for 32-bit vs 64-bit support */
980305ac5f9Spatrick 		KASSERT((map->dm_segs[i].ds_addr >> 32) == 0);
981305ac5f9Spatrick 
982305ac5f9Spatrick 		txd->sd_tdes0 = (uint32_t)map->dm_segs[i].ds_addr;
983305ac5f9Spatrick 		txd->sd_tdes1 = (uint32_t)(map->dm_segs[i].ds_addr >> 32);
984305ac5f9Spatrick 		txd->sd_tdes2 = map->dm_segs[i].ds_len;
985305ac5f9Spatrick 		txd->sd_tdes3 = m->m_pkthdr.len;
986305ac5f9Spatrick 		if (i == 0)
987305ac5f9Spatrick 			txd->sd_tdes3 |= TDES3_FS;
988305ac5f9Spatrick 		if (i == (map->dm_nsegs - 1)) {
989305ac5f9Spatrick 			txd->sd_tdes2 |= TDES2_IC;
990305ac5f9Spatrick 			txd->sd_tdes3 |= TDES3_LS;
991305ac5f9Spatrick 		}
992305ac5f9Spatrick 		if (i != 0)
993305ac5f9Spatrick 			txd->sd_tdes3 |= TDES3_OWN;
994305ac5f9Spatrick 
995305ac5f9Spatrick 		bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring),
996305ac5f9Spatrick 		    frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE);
997305ac5f9Spatrick 
998305ac5f9Spatrick 		cur = frag;
999305ac5f9Spatrick 		if (frag == (DWQE_NTXDESC - 1)) {
1000305ac5f9Spatrick 			txd = &sc->sc_txdesc[0];
1001305ac5f9Spatrick 			frag = 0;
1002305ac5f9Spatrick 		} else {
1003305ac5f9Spatrick 			txd++;
1004305ac5f9Spatrick 			frag++;
1005305ac5f9Spatrick 		}
1006305ac5f9Spatrick 		KASSERT(frag != sc->sc_tx_cons);
1007305ac5f9Spatrick 	}
1008305ac5f9Spatrick 
1009305ac5f9Spatrick 	txd_start->sd_tdes3 |= TDES3_OWN;
1010305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring),
1011305ac5f9Spatrick 	    *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE);
1012305ac5f9Spatrick 
1013305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring) +
1014*4fa84378Skettenis 	    frag * sizeof(*txd));
1015305ac5f9Spatrick 
1016305ac5f9Spatrick 	KASSERT(sc->sc_txbuf[cur].tb_m == NULL);
1017305ac5f9Spatrick 	sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map;
1018305ac5f9Spatrick 	sc->sc_txbuf[cur].tb_map = map;
1019305ac5f9Spatrick 	sc->sc_txbuf[cur].tb_m = m;
1020305ac5f9Spatrick 
1021305ac5f9Spatrick 	*idx = frag;
1022305ac5f9Spatrick 	*used += map->dm_nsegs;
1023305ac5f9Spatrick 
1024305ac5f9Spatrick 	return (0);
1025305ac5f9Spatrick }
1026305ac5f9Spatrick 
1027305ac5f9Spatrick void
1028305ac5f9Spatrick dwqe_reset(struct dwqe_softc *sc)
1029305ac5f9Spatrick {
1030305ac5f9Spatrick 	int n;
1031305ac5f9Spatrick 
1032305ac5f9Spatrick 	dwqe_write(sc, GMAC_BUS_MODE, dwqe_read(sc, GMAC_BUS_MODE) |
1033305ac5f9Spatrick 	    GMAC_BUS_MODE_SWR);
1034305ac5f9Spatrick 
1035305ac5f9Spatrick 	for (n = 0; n < 30000; n++) {
1036305ac5f9Spatrick 		if ((dwqe_read(sc, GMAC_BUS_MODE) &
1037305ac5f9Spatrick 		    GMAC_BUS_MODE_SWR) == 0)
1038305ac5f9Spatrick 			return;
1039305ac5f9Spatrick 		delay(10);
1040305ac5f9Spatrick 	}
1041305ac5f9Spatrick 
1042305ac5f9Spatrick 	printf("%s: reset timeout\n", sc->sc_dev.dv_xname);
1043305ac5f9Spatrick }
1044305ac5f9Spatrick 
1045305ac5f9Spatrick struct dwqe_dmamem *
1046305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *sc, bus_size_t size, bus_size_t align)
1047305ac5f9Spatrick {
1048305ac5f9Spatrick 	struct dwqe_dmamem *tdm;
1049305ac5f9Spatrick 	int nsegs;
1050305ac5f9Spatrick 
1051305ac5f9Spatrick 	tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO);
1052305ac5f9Spatrick 	tdm->tdm_size = size;
1053305ac5f9Spatrick 
1054305ac5f9Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1055305ac5f9Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0)
1056305ac5f9Spatrick 		goto tdmfree;
1057305ac5f9Spatrick 
1058305ac5f9Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1,
1059305ac5f9Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
1060305ac5f9Spatrick 		goto destroy;
1061305ac5f9Spatrick 
1062305ac5f9Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size,
1063305ac5f9Spatrick 	    &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
1064305ac5f9Spatrick 		goto free;
1065305ac5f9Spatrick 
1066305ac5f9Spatrick 	if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size,
1067305ac5f9Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
1068305ac5f9Spatrick 		goto unmap;
1069305ac5f9Spatrick 
1070305ac5f9Spatrick 	bzero(tdm->tdm_kva, size);
1071305ac5f9Spatrick 
1072305ac5f9Spatrick 	return (tdm);
1073305ac5f9Spatrick 
1074305ac5f9Spatrick unmap:
1075305ac5f9Spatrick 	bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size);
1076305ac5f9Spatrick free:
1077305ac5f9Spatrick 	bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1);
1078305ac5f9Spatrick destroy:
1079305ac5f9Spatrick 	bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map);
1080305ac5f9Spatrick tdmfree:
1081305ac5f9Spatrick 	free(tdm, M_DEVBUF, 0);
1082305ac5f9Spatrick 
1083305ac5f9Spatrick 	return (NULL);
1084305ac5f9Spatrick }
1085305ac5f9Spatrick 
1086305ac5f9Spatrick void
1087305ac5f9Spatrick dwqe_dmamem_free(struct dwqe_softc *sc, struct dwqe_dmamem *tdm)
1088305ac5f9Spatrick {
1089305ac5f9Spatrick 	bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size);
1090305ac5f9Spatrick 	bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1);
1091305ac5f9Spatrick 	bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map);
1092305ac5f9Spatrick 	free(tdm, M_DEVBUF, 0);
1093305ac5f9Spatrick }
1094305ac5f9Spatrick 
1095305ac5f9Spatrick struct mbuf *
1096305ac5f9Spatrick dwqe_alloc_mbuf(struct dwqe_softc *sc, bus_dmamap_t map)
1097305ac5f9Spatrick {
1098305ac5f9Spatrick 	struct mbuf *m = NULL;
1099305ac5f9Spatrick 
1100305ac5f9Spatrick 	m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES);
1101305ac5f9Spatrick 	if (!m)
1102305ac5f9Spatrick 		return (NULL);
1103305ac5f9Spatrick 	m->m_len = m->m_pkthdr.len = MCLBYTES;
1104305ac5f9Spatrick 	m_adj(m, ETHER_ALIGN);
1105305ac5f9Spatrick 
1106305ac5f9Spatrick 	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
1107305ac5f9Spatrick 		printf("%s: could not load mbuf DMA map", DEVNAME(sc));
1108305ac5f9Spatrick 		m_freem(m);
1109305ac5f9Spatrick 		return (NULL);
1110305ac5f9Spatrick 	}
1111305ac5f9Spatrick 
1112305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, map, 0,
1113305ac5f9Spatrick 	    m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
1114305ac5f9Spatrick 
1115305ac5f9Spatrick 	return (m);
1116305ac5f9Spatrick }
1117305ac5f9Spatrick 
1118305ac5f9Spatrick void
1119305ac5f9Spatrick dwqe_fill_rx_ring(struct dwqe_softc *sc)
1120305ac5f9Spatrick {
1121305ac5f9Spatrick 	struct dwqe_desc *rxd;
1122305ac5f9Spatrick 	struct dwqe_buf *rxb;
1123305ac5f9Spatrick 	u_int slots;
1124305ac5f9Spatrick 
1125305ac5f9Spatrick 	for (slots = if_rxr_get(&sc->sc_rx_ring, DWQE_NRXDESC);
1126305ac5f9Spatrick 	    slots > 0; slots--) {
1127305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[sc->sc_rx_prod];
1128305ac5f9Spatrick 		rxb->tb_m = dwqe_alloc_mbuf(sc, rxb->tb_map);
1129305ac5f9Spatrick 		if (rxb->tb_m == NULL)
1130305ac5f9Spatrick 			break;
1131305ac5f9Spatrick 
1132305ac5f9Spatrick 		/* TODO: check for 32-bit vs 64-bit support */
1133*4fa84378Skettenis 		KASSERT((rxb->tb_map->dm_segs[0].ds_addr >> 32) == 0);
1134305ac5f9Spatrick 
1135305ac5f9Spatrick 		rxd = &sc->sc_rxdesc[sc->sc_rx_prod];
1136*4fa84378Skettenis 		rxd->sd_tdes0 = (uint32_t)rxb->tb_map->dm_segs[0].ds_addr;
1137*4fa84378Skettenis 		rxd->sd_tdes1 = (uint32_t)(rxb->tb_map->dm_segs[0].ds_addr >> 32);
1138305ac5f9Spatrick 		rxd->sd_tdes2 = 0;
1139305ac5f9Spatrick 		rxd->sd_tdes3 = RDES3_OWN | RDES3_IC | RDES3_BUF1V;
1140305ac5f9Spatrick 
1141305ac5f9Spatrick 		if (sc->sc_rx_prod == (DWQE_NRXDESC - 1))
1142305ac5f9Spatrick 			sc->sc_rx_prod = 0;
1143305ac5f9Spatrick 		else
1144305ac5f9Spatrick 			sc->sc_rx_prod++;
1145305ac5f9Spatrick 	}
1146305ac5f9Spatrick 	if_rxr_put(&sc->sc_rx_ring, slots);
1147305ac5f9Spatrick 
1148305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring) +
1149305ac5f9Spatrick 	    sc->sc_rx_prod * sizeof(*rxd));
1150305ac5f9Spatrick 
1151305ac5f9Spatrick 	if (if_rxr_inuse(&sc->sc_rx_ring) == 0)
1152305ac5f9Spatrick 		timeout_add(&sc->sc_rxto, 1);
1153305ac5f9Spatrick }
1154