xref: /openbsd/sys/dev/ic/dwqe.c (revision 6e9149a4)
1*6e9149a4Sstsp /*	$OpenBSD: dwqe.c,v 1.14 2023/10/11 12:52:00 stsp 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 
38305ac5f9Spatrick #include <net/if.h>
39305ac5f9Spatrick #include <net/if_media.h>
40305ac5f9Spatrick 
41305ac5f9Spatrick #include <dev/mii/mii.h>
42305ac5f9Spatrick #include <dev/mii/miivar.h>
43305ac5f9Spatrick 
44305ac5f9Spatrick #if NBPFILTER > 0
45305ac5f9Spatrick #include <net/bpf.h>
46305ac5f9Spatrick #endif
47305ac5f9Spatrick 
48305ac5f9Spatrick #include <netinet/in.h>
49305ac5f9Spatrick #include <netinet/if_ether.h>
50305ac5f9Spatrick 
51305ac5f9Spatrick #include <dev/ic/dwqevar.h>
52305ac5f9Spatrick #include <dev/ic/dwqereg.h>
53305ac5f9Spatrick 
54305ac5f9Spatrick struct cfdriver dwqe_cd = {
55305ac5f9Spatrick 	NULL, "dwqe", DV_IFNET
56305ac5f9Spatrick };
57305ac5f9Spatrick 
58305ac5f9Spatrick uint32_t dwqe_read(struct dwqe_softc *, bus_addr_t);
59305ac5f9Spatrick void	dwqe_write(struct dwqe_softc *, bus_addr_t, uint32_t);
60305ac5f9Spatrick 
61305ac5f9Spatrick int	dwqe_ioctl(struct ifnet *, u_long, caddr_t);
62305ac5f9Spatrick void	dwqe_start(struct ifqueue *);
63305ac5f9Spatrick void	dwqe_watchdog(struct ifnet *);
64305ac5f9Spatrick 
65305ac5f9Spatrick int	dwqe_media_change(struct ifnet *);
66305ac5f9Spatrick void	dwqe_media_status(struct ifnet *, struct ifmediareq *);
67305ac5f9Spatrick 
6845f5f3c8Sdlg void	dwqe_mii_attach(struct dwqe_softc *);
69305ac5f9Spatrick int	dwqe_mii_readreg(struct device *, int, int);
70305ac5f9Spatrick void	dwqe_mii_writereg(struct device *, int, int, int);
71305ac5f9Spatrick void	dwqe_mii_statchg(struct device *);
72305ac5f9Spatrick 
73305ac5f9Spatrick void	dwqe_lladdr_read(struct dwqe_softc *, uint8_t *);
74305ac5f9Spatrick void	dwqe_lladdr_write(struct dwqe_softc *);
75305ac5f9Spatrick 
76305ac5f9Spatrick void	dwqe_tick(void *);
77305ac5f9Spatrick void	dwqe_rxtick(void *);
78305ac5f9Spatrick 
79305ac5f9Spatrick int	dwqe_intr(void *);
80305ac5f9Spatrick void	dwqe_tx_proc(struct dwqe_softc *);
81305ac5f9Spatrick void	dwqe_rx_proc(struct dwqe_softc *);
82305ac5f9Spatrick 
83305ac5f9Spatrick void	dwqe_up(struct dwqe_softc *);
84305ac5f9Spatrick void	dwqe_down(struct dwqe_softc *);
85305ac5f9Spatrick void	dwqe_iff(struct dwqe_softc *);
86305ac5f9Spatrick int	dwqe_encap(struct dwqe_softc *, struct mbuf *, int *, int *);
87305ac5f9Spatrick 
88305ac5f9Spatrick void	dwqe_reset(struct dwqe_softc *);
89305ac5f9Spatrick 
90305ac5f9Spatrick struct dwqe_dmamem *
91305ac5f9Spatrick 	dwqe_dmamem_alloc(struct dwqe_softc *, bus_size_t, bus_size_t);
92305ac5f9Spatrick void	dwqe_dmamem_free(struct dwqe_softc *, struct dwqe_dmamem *);
93305ac5f9Spatrick struct mbuf *dwqe_alloc_mbuf(struct dwqe_softc *, bus_dmamap_t);
94305ac5f9Spatrick void	dwqe_fill_rx_ring(struct dwqe_softc *);
95305ac5f9Spatrick 
96305ac5f9Spatrick int
97305ac5f9Spatrick dwqe_attach(struct dwqe_softc *sc)
98305ac5f9Spatrick {
99305ac5f9Spatrick 	struct ifnet *ifp;
100305ac5f9Spatrick 	uint32_t version, mode;
101305ac5f9Spatrick 	int i;
102305ac5f9Spatrick 
103305ac5f9Spatrick 	version = dwqe_read(sc, GMAC_VERSION);
1044fa84378Skettenis 	printf(": rev 0x%02x, address %s\n", version & GMAC_VERSION_SNPS_MASK,
105305ac5f9Spatrick 	    ether_sprintf(sc->sc_lladdr));
106305ac5f9Spatrick 
107305ac5f9Spatrick 	for (i = 0; i < 4; i++)
108305ac5f9Spatrick 		sc->sc_hw_feature[i] = dwqe_read(sc, GMAC_MAC_HW_FEATURE(i));
109305ac5f9Spatrick 
11047707f8eSdlg 	timeout_set(&sc->sc_phy_tick, dwqe_tick, sc);
111305ac5f9Spatrick 	timeout_set(&sc->sc_rxto, dwqe_rxtick, sc);
112305ac5f9Spatrick 
113305ac5f9Spatrick 	ifp = &sc->sc_ac.ac_if;
114305ac5f9Spatrick 	ifp->if_softc = sc;
115305ac5f9Spatrick 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
116305ac5f9Spatrick 	ifp->if_xflags = IFXF_MPSAFE;
117305ac5f9Spatrick 	ifp->if_ioctl = dwqe_ioctl;
118305ac5f9Spatrick 	ifp->if_qstart = dwqe_start;
119305ac5f9Spatrick 	ifp->if_watchdog = dwqe_watchdog;
120305ac5f9Spatrick 	ifq_set_maxlen(&ifp->if_snd, DWQE_NTXDESC - 1);
121305ac5f9Spatrick 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
122305ac5f9Spatrick 
123305ac5f9Spatrick 	ifp->if_capabilities = IFCAP_VLAN_MTU;
124305ac5f9Spatrick 
125305ac5f9Spatrick 	sc->sc_mii.mii_ifp = ifp;
126305ac5f9Spatrick 	sc->sc_mii.mii_readreg = dwqe_mii_readreg;
127305ac5f9Spatrick 	sc->sc_mii.mii_writereg = dwqe_mii_writereg;
128305ac5f9Spatrick 	sc->sc_mii.mii_statchg = dwqe_mii_statchg;
129305ac5f9Spatrick 
130305ac5f9Spatrick 	ifmedia_init(&sc->sc_media, 0, dwqe_media_change, dwqe_media_status);
131305ac5f9Spatrick 
132305ac5f9Spatrick 	dwqe_reset(sc);
133305ac5f9Spatrick 
134305ac5f9Spatrick 	/* Configure DMA engine. */
135305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_SYS_BUS_MODE);
136305ac5f9Spatrick 	if (sc->sc_fixed_burst)
137305ac5f9Spatrick 		mode |= GMAC_SYS_BUS_MODE_FB;
138305ac5f9Spatrick 	if (sc->sc_mixed_burst)
139305ac5f9Spatrick 		mode |= GMAC_SYS_BUS_MODE_MB;
140305ac5f9Spatrick 	if (sc->sc_aal)
141305ac5f9Spatrick 		mode |= GMAC_SYS_BUS_MODE_AAL;
142305ac5f9Spatrick 	dwqe_write(sc, GMAC_SYS_BUS_MODE, mode);
143305ac5f9Spatrick 
144305ac5f9Spatrick 	/* Configure channel 0. */
145305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_CHAN_CONTROL(0));
146305ac5f9Spatrick 	if (sc->sc_8xpbl)
147305ac5f9Spatrick 		mode |= GMAC_CHAN_CONTROL_8XPBL;
148305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_CONTROL(0), mode);
149305ac5f9Spatrick 
150305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0));
151305ac5f9Spatrick 	mode &= ~GMAC_CHAN_TX_CONTROL_PBL_MASK;
152305ac5f9Spatrick 	mode |= sc->sc_txpbl << GMAC_CHAN_TX_CONTROL_PBL_SHIFT;
153305ac5f9Spatrick 	mode |= GMAC_CHAN_TX_CONTROL_OSP;
154305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), mode);
155f6ce44eeSjsg 	mode = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0));
156305ac5f9Spatrick 	mode &= ~GMAC_CHAN_RX_CONTROL_RPBL_MASK;
157305ac5f9Spatrick 	mode |= sc->sc_rxpbl << GMAC_CHAN_RX_CONTROL_RPBL_SHIFT;
158305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), mode);
159305ac5f9Spatrick 
160305ac5f9Spatrick 	/* Configure AXI master. */
161305ac5f9Spatrick 	if (sc->sc_axi_config) {
162305ac5f9Spatrick 		int i;
163305ac5f9Spatrick 
164305ac5f9Spatrick 		mode = dwqe_read(sc, GMAC_SYS_BUS_MODE);
165305ac5f9Spatrick 
166305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_EN_LPI;
167305ac5f9Spatrick 		if (sc->sc_lpi_en)
168305ac5f9Spatrick 			mode |= GMAC_SYS_BUS_MODE_EN_LPI;
169305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_LPI_XIT_FRM;
170305ac5f9Spatrick 		if (sc->sc_xit_frm)
171305ac5f9Spatrick 			mode |= GMAC_SYS_BUS_MODE_LPI_XIT_FRM;
172305ac5f9Spatrick 
173305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_WR_OSR_LMT_MASK;
174305ac5f9Spatrick 		mode |= (sc->sc_wr_osr_lmt << GMAC_SYS_BUS_MODE_WR_OSR_LMT_SHIFT);
175305ac5f9Spatrick 		mode &= ~GMAC_SYS_BUS_MODE_RD_OSR_LMT_MASK;
176305ac5f9Spatrick 		mode |= (sc->sc_rd_osr_lmt << GMAC_SYS_BUS_MODE_RD_OSR_LMT_SHIFT);
177305ac5f9Spatrick 
178305ac5f9Spatrick 		for (i = 0; i < nitems(sc->sc_blen); i++) {
179305ac5f9Spatrick 			switch (sc->sc_blen[i]) {
180305ac5f9Spatrick 			case 256:
181305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_256;
182305ac5f9Spatrick 				break;
183305ac5f9Spatrick 			case 128:
184305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_128;
185305ac5f9Spatrick 				break;
186305ac5f9Spatrick 			case 64:
187305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_64;
188305ac5f9Spatrick 				break;
189305ac5f9Spatrick 			case 32:
190305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_32;
191305ac5f9Spatrick 				break;
192305ac5f9Spatrick 			case 16:
193305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_16;
194305ac5f9Spatrick 				break;
195305ac5f9Spatrick 			case 8:
196305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_8;
197305ac5f9Spatrick 				break;
198305ac5f9Spatrick 			case 4:
199305ac5f9Spatrick 				mode |= GMAC_SYS_BUS_MODE_BLEN_4;
200305ac5f9Spatrick 				break;
201305ac5f9Spatrick 			}
202305ac5f9Spatrick 		}
203305ac5f9Spatrick 
204305ac5f9Spatrick 		dwqe_write(sc, GMAC_SYS_BUS_MODE, mode);
205305ac5f9Spatrick 	}
206305ac5f9Spatrick 
20745f5f3c8Sdlg 	if (!sc->sc_fixed_link)
20845f5f3c8Sdlg 		dwqe_mii_attach(sc);
20945f5f3c8Sdlg 
21045f5f3c8Sdlg 	if_attach(ifp);
21145f5f3c8Sdlg 	ether_ifattach(ifp);
21245f5f3c8Sdlg 
21345f5f3c8Sdlg 	/* Disable interrupts. */
21445f5f3c8Sdlg 	dwqe_write(sc, GMAC_INT_EN, 0);
21545f5f3c8Sdlg 	dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0);
21645f5f3c8Sdlg 
21745f5f3c8Sdlg 	return 0;
21845f5f3c8Sdlg }
21945f5f3c8Sdlg 
22045f5f3c8Sdlg void
22145f5f3c8Sdlg dwqe_mii_attach(struct dwqe_softc *sc)
22245f5f3c8Sdlg {
22345f5f3c8Sdlg 	int mii_flags = 0;
22445f5f3c8Sdlg 
225e9f49f11Skettenis 	switch (sc->sc_phy_mode) {
226e9f49f11Skettenis 	case DWQE_PHY_MODE_RGMII:
227e9f49f11Skettenis 		mii_flags |= MIIF_SETDELAY;
228e9f49f11Skettenis 		break;
229e9f49f11Skettenis 	case DWQE_PHY_MODE_RGMII_ID:
230e9f49f11Skettenis 		mii_flags |= MIIF_SETDELAY | MIIF_RXID | MIIF_TXID;
231e9f49f11Skettenis 		break;
232e9f49f11Skettenis 	case DWQE_PHY_MODE_RGMII_RXID:
233e9f49f11Skettenis 		mii_flags |= MIIF_SETDELAY | MIIF_RXID;
234e9f49f11Skettenis 		break;
235e9f49f11Skettenis 	case DWQE_PHY_MODE_RGMII_TXID:
236e9f49f11Skettenis 		mii_flags |= MIIF_SETDELAY | MIIF_TXID;
237e9f49f11Skettenis 		break;
238e9f49f11Skettenis 	default:
239e9f49f11Skettenis 		break;
240e9f49f11Skettenis 	}
241e9f49f11Skettenis 
242305ac5f9Spatrick 	mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, sc->sc_phyloc,
243e9f49f11Skettenis 	    (sc->sc_phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY, mii_flags);
244305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
245305ac5f9Spatrick 		printf("%s: no PHY found!\n", sc->sc_dev.dv_xname);
246305ac5f9Spatrick 		ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
247305ac5f9Spatrick 		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
248305ac5f9Spatrick 	} else
249305ac5f9Spatrick 		ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO);
250305ac5f9Spatrick }
251305ac5f9Spatrick 
252305ac5f9Spatrick uint32_t
253305ac5f9Spatrick dwqe_read(struct dwqe_softc *sc, bus_addr_t addr)
254305ac5f9Spatrick {
255305ac5f9Spatrick 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr);
256305ac5f9Spatrick }
257305ac5f9Spatrick 
258305ac5f9Spatrick void
259305ac5f9Spatrick dwqe_write(struct dwqe_softc *sc, bus_addr_t addr, uint32_t data)
260305ac5f9Spatrick {
261305ac5f9Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, data);
262305ac5f9Spatrick }
263305ac5f9Spatrick 
264305ac5f9Spatrick void
265305ac5f9Spatrick dwqe_lladdr_read(struct dwqe_softc *sc, uint8_t *lladdr)
266305ac5f9Spatrick {
267305ac5f9Spatrick 	uint32_t machi, maclo;
268305ac5f9Spatrick 
269305ac5f9Spatrick 	machi = dwqe_read(sc, GMAC_MAC_ADDR0_HI);
270305ac5f9Spatrick 	maclo = dwqe_read(sc, GMAC_MAC_ADDR0_LO);
271305ac5f9Spatrick 
272305ac5f9Spatrick 	if (machi || maclo) {
273305ac5f9Spatrick 		lladdr[0] = (maclo >> 0) & 0xff;
274305ac5f9Spatrick 		lladdr[1] = (maclo >> 8) & 0xff;
275305ac5f9Spatrick 		lladdr[2] = (maclo >> 16) & 0xff;
276305ac5f9Spatrick 		lladdr[3] = (maclo >> 24) & 0xff;
277305ac5f9Spatrick 		lladdr[4] = (machi >> 0) & 0xff;
278305ac5f9Spatrick 		lladdr[5] = (machi >> 8) & 0xff;
279305ac5f9Spatrick 	} else {
280305ac5f9Spatrick 		ether_fakeaddr(&sc->sc_ac.ac_if);
281305ac5f9Spatrick 	}
282305ac5f9Spatrick }
283305ac5f9Spatrick 
284305ac5f9Spatrick void
285305ac5f9Spatrick dwqe_lladdr_write(struct dwqe_softc *sc)
286305ac5f9Spatrick {
287305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_ADDR0_HI,
288305ac5f9Spatrick 	    sc->sc_lladdr[5] << 8 | sc->sc_lladdr[4] << 0);
289305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_ADDR0_LO,
290305ac5f9Spatrick 	    sc->sc_lladdr[3] << 24 | sc->sc_lladdr[2] << 16 |
291305ac5f9Spatrick 	    sc->sc_lladdr[1] << 8 | sc->sc_lladdr[0] << 0);
292305ac5f9Spatrick }
293305ac5f9Spatrick 
294305ac5f9Spatrick void
295305ac5f9Spatrick dwqe_start(struct ifqueue *ifq)
296305ac5f9Spatrick {
297305ac5f9Spatrick 	struct ifnet *ifp = ifq->ifq_if;
298305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
299305ac5f9Spatrick 	struct mbuf *m;
300305ac5f9Spatrick 	int error, idx, left, used;
301305ac5f9Spatrick 
302305ac5f9Spatrick 	if (!(ifp->if_flags & IFF_RUNNING))
303305ac5f9Spatrick 		return;
304305ac5f9Spatrick 	if (ifq_is_oactive(&ifp->if_snd))
305305ac5f9Spatrick 		return;
306305ac5f9Spatrick 	if (ifq_empty(&ifp->if_snd))
307305ac5f9Spatrick 		return;
308305ac5f9Spatrick 	if (!sc->sc_link)
309305ac5f9Spatrick 		return;
310305ac5f9Spatrick 
311305ac5f9Spatrick 	idx = sc->sc_tx_prod;
312305ac5f9Spatrick 	left = sc->sc_tx_cons;
313305ac5f9Spatrick 	if (left <= idx)
314305ac5f9Spatrick 		left += DWQE_NTXDESC;
315305ac5f9Spatrick 	left -= idx;
316305ac5f9Spatrick 	used = 0;
317305ac5f9Spatrick 
318305ac5f9Spatrick 	for (;;) {
319305ac5f9Spatrick 		if (used + DWQE_NTXSEGS + 1 > left) {
320305ac5f9Spatrick 			ifq_set_oactive(ifq);
321305ac5f9Spatrick 			break;
322305ac5f9Spatrick 		}
323305ac5f9Spatrick 
324305ac5f9Spatrick 		m = ifq_dequeue(ifq);
325305ac5f9Spatrick 		if (m == NULL)
326305ac5f9Spatrick 			break;
327305ac5f9Spatrick 
328305ac5f9Spatrick 		error = dwqe_encap(sc, m, &idx, &used);
329305ac5f9Spatrick 		if (error == EFBIG) {
330305ac5f9Spatrick 			m_freem(m); /* give up: drop it */
331305ac5f9Spatrick 			ifp->if_oerrors++;
332305ac5f9Spatrick 			continue;
333305ac5f9Spatrick 		}
334305ac5f9Spatrick 
335305ac5f9Spatrick #if NBPFILTER > 0
336305ac5f9Spatrick 		if (ifp->if_bpf)
337305ac5f9Spatrick 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
338305ac5f9Spatrick #endif
339305ac5f9Spatrick 	}
340305ac5f9Spatrick 
341305ac5f9Spatrick 	if (sc->sc_tx_prod != idx) {
342305ac5f9Spatrick 		sc->sc_tx_prod = idx;
343305ac5f9Spatrick 
344305ac5f9Spatrick 		/* Set a timeout in case the chip goes out to lunch. */
345305ac5f9Spatrick 		ifp->if_timer = 5;
346305ac5f9Spatrick 	}
347305ac5f9Spatrick }
348305ac5f9Spatrick 
349305ac5f9Spatrick int
350305ac5f9Spatrick dwqe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
351305ac5f9Spatrick {
352305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
353305ac5f9Spatrick 	struct ifreq *ifr = (struct ifreq *)addr;
354305ac5f9Spatrick 	int error = 0, s;
355305ac5f9Spatrick 
356305ac5f9Spatrick 	s = splnet();
357305ac5f9Spatrick 
358305ac5f9Spatrick 	switch (cmd) {
359305ac5f9Spatrick 	case SIOCSIFADDR:
360305ac5f9Spatrick 		ifp->if_flags |= IFF_UP;
361305ac5f9Spatrick 		/* FALLTHROUGH */
362305ac5f9Spatrick 	case SIOCSIFFLAGS:
363305ac5f9Spatrick 		if (ifp->if_flags & IFF_UP) {
364305ac5f9Spatrick 			if (ifp->if_flags & IFF_RUNNING)
365305ac5f9Spatrick 				error = ENETRESET;
366305ac5f9Spatrick 			else
367305ac5f9Spatrick 				dwqe_up(sc);
368305ac5f9Spatrick 		} else {
369305ac5f9Spatrick 			if (ifp->if_flags & IFF_RUNNING)
370305ac5f9Spatrick 				dwqe_down(sc);
371305ac5f9Spatrick 		}
372305ac5f9Spatrick 		break;
373305ac5f9Spatrick 
374305ac5f9Spatrick 	case SIOCGIFMEDIA:
375305ac5f9Spatrick 	case SIOCSIFMEDIA:
37645f5f3c8Sdlg 		if (sc->sc_fixed_link)
37745f5f3c8Sdlg 			error = ENOTTY;
37845f5f3c8Sdlg 		else
379305ac5f9Spatrick 			error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
380305ac5f9Spatrick 		break;
381305ac5f9Spatrick 
382305ac5f9Spatrick 	case SIOCGIFRXR:
383305ac5f9Spatrick 		error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data,
384305ac5f9Spatrick 		    NULL, MCLBYTES, &sc->sc_rx_ring);
385305ac5f9Spatrick 		break;
386305ac5f9Spatrick 
387305ac5f9Spatrick 	default:
388305ac5f9Spatrick 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr);
389305ac5f9Spatrick 		break;
390305ac5f9Spatrick 	}
391305ac5f9Spatrick 
392305ac5f9Spatrick 	if (error == ENETRESET) {
393305ac5f9Spatrick 		if (ifp->if_flags & IFF_RUNNING)
394305ac5f9Spatrick 			dwqe_iff(sc);
395305ac5f9Spatrick 		error = 0;
396305ac5f9Spatrick 	}
397305ac5f9Spatrick 
398305ac5f9Spatrick 	splx(s);
399305ac5f9Spatrick 	return (error);
400305ac5f9Spatrick }
401305ac5f9Spatrick 
402305ac5f9Spatrick void
403305ac5f9Spatrick dwqe_watchdog(struct ifnet *ifp)
404305ac5f9Spatrick {
405305ac5f9Spatrick 	printf("%s\n", __func__);
406305ac5f9Spatrick }
407305ac5f9Spatrick 
408305ac5f9Spatrick int
409305ac5f9Spatrick dwqe_media_change(struct ifnet *ifp)
410305ac5f9Spatrick {
411305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
412305ac5f9Spatrick 
413305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
414305ac5f9Spatrick 		mii_mediachg(&sc->sc_mii);
415305ac5f9Spatrick 
416305ac5f9Spatrick 	return (0);
417305ac5f9Spatrick }
418305ac5f9Spatrick 
419305ac5f9Spatrick void
420305ac5f9Spatrick dwqe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
421305ac5f9Spatrick {
422305ac5f9Spatrick 	struct dwqe_softc *sc = ifp->if_softc;
423305ac5f9Spatrick 
424305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
425305ac5f9Spatrick 		mii_pollstat(&sc->sc_mii);
426305ac5f9Spatrick 		ifmr->ifm_active = sc->sc_mii.mii_media_active;
427305ac5f9Spatrick 		ifmr->ifm_status = sc->sc_mii.mii_media_status;
428305ac5f9Spatrick 	}
429305ac5f9Spatrick }
430305ac5f9Spatrick 
431305ac5f9Spatrick int
432305ac5f9Spatrick dwqe_mii_readreg(struct device *self, int phy, int reg)
433305ac5f9Spatrick {
434305ac5f9Spatrick 	struct dwqe_softc *sc = (void *)self;
435305ac5f9Spatrick 	int n;
436305ac5f9Spatrick 
437305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_MDIO_ADDR,
4380738886aSkettenis 	    (sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT) |
439305ac5f9Spatrick 	    (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) |
440305ac5f9Spatrick 	    (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) |
441305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GOC_READ |
442305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GB);
443305ac5f9Spatrick 
4449fb70083Sdlg 	for (n = 0; n < 2000; n++) {
4459fb70083Sdlg 		delay(10);
446305ac5f9Spatrick 		if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0)
447305ac5f9Spatrick 			return dwqe_read(sc, GMAC_MAC_MDIO_DATA);
448305ac5f9Spatrick 	}
449305ac5f9Spatrick 
450305ac5f9Spatrick 	printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname);
451305ac5f9Spatrick 	return (0);
452305ac5f9Spatrick }
453305ac5f9Spatrick 
454305ac5f9Spatrick void
455305ac5f9Spatrick dwqe_mii_writereg(struct device *self, int phy, int reg, int val)
456305ac5f9Spatrick {
457305ac5f9Spatrick 	struct dwqe_softc *sc = (void *)self;
458305ac5f9Spatrick 	int n;
459305ac5f9Spatrick 
460305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_MDIO_DATA, val);
461305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_MDIO_ADDR,
4620738886aSkettenis 	    (sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT) |
463305ac5f9Spatrick 	    (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) |
464305ac5f9Spatrick 	    (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) |
465305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GOC_WRITE |
466305ac5f9Spatrick 	    GMAC_MAC_MDIO_ADDR_GB);
4679fb70083Sdlg 
4689fb70083Sdlg 	for (n = 0; n < 2000; n++) {
4699fb70083Sdlg 		delay(10);
470305ac5f9Spatrick 		if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0)
471305ac5f9Spatrick 			return;
472305ac5f9Spatrick 	}
473305ac5f9Spatrick 
474305ac5f9Spatrick 	printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname);
475305ac5f9Spatrick }
476305ac5f9Spatrick 
477305ac5f9Spatrick void
478305ac5f9Spatrick dwqe_mii_statchg(struct device *self)
479305ac5f9Spatrick {
480305ac5f9Spatrick 	struct dwqe_softc *sc = (void *)self;
481566e78fcSdlg 	struct ifnet *ifp = &sc->sc_ac.ac_if;
482305ac5f9Spatrick 	uint32_t conf;
483305ac5f9Spatrick 
484305ac5f9Spatrick 	conf = dwqe_read(sc, GMAC_MAC_CONF);
485305ac5f9Spatrick 	conf &= ~(GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES);
486305ac5f9Spatrick 
487566e78fcSdlg 	switch (ifp->if_baudrate) {
488566e78fcSdlg 	case IF_Mbps(1000):
489305ac5f9Spatrick 		sc->sc_link = 1;
490305ac5f9Spatrick 		break;
491566e78fcSdlg 	case IF_Mbps(100):
492305ac5f9Spatrick 		conf |= GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES;
493305ac5f9Spatrick 		sc->sc_link = 1;
494305ac5f9Spatrick 		break;
495566e78fcSdlg 	case IF_Mbps(10):
496305ac5f9Spatrick 		conf |= GMAC_MAC_CONF_PS;
497305ac5f9Spatrick 		sc->sc_link = 1;
498305ac5f9Spatrick 		break;
499305ac5f9Spatrick 	default:
500305ac5f9Spatrick 		sc->sc_link = 0;
501305ac5f9Spatrick 		return;
502305ac5f9Spatrick 	}
503305ac5f9Spatrick 
504305ac5f9Spatrick 	if (sc->sc_link == 0)
505305ac5f9Spatrick 		return;
506305ac5f9Spatrick 
507305ac5f9Spatrick 	conf &= ~GMAC_MAC_CONF_DM;
508566e78fcSdlg 	if (ifp->if_link_state == LINK_STATE_FULL_DUPLEX)
509305ac5f9Spatrick 		conf |= GMAC_MAC_CONF_DM;
510305ac5f9Spatrick 
511305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, conf);
512305ac5f9Spatrick }
513305ac5f9Spatrick 
514305ac5f9Spatrick void
515305ac5f9Spatrick dwqe_tick(void *arg)
516305ac5f9Spatrick {
517305ac5f9Spatrick 	struct dwqe_softc *sc = arg;
518305ac5f9Spatrick 	int s;
519305ac5f9Spatrick 
520305ac5f9Spatrick 	s = splnet();
521305ac5f9Spatrick 	mii_tick(&sc->sc_mii);
522305ac5f9Spatrick 	splx(s);
523305ac5f9Spatrick 
52447707f8eSdlg 	timeout_add_sec(&sc->sc_phy_tick, 1);
525305ac5f9Spatrick }
526305ac5f9Spatrick 
527305ac5f9Spatrick void
528305ac5f9Spatrick dwqe_rxtick(void *arg)
529305ac5f9Spatrick {
530305ac5f9Spatrick 	struct dwqe_softc *sc = arg;
531305ac5f9Spatrick 	int s;
532305ac5f9Spatrick 
533305ac5f9Spatrick 	s = splnet();
534305ac5f9Spatrick 
535305ac5f9Spatrick 	/* TODO: disable RXQ? */
536305ac5f9Spatrick 	printf("%s:%d\n", __func__, __LINE__);
537305ac5f9Spatrick 
538305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring),
539305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_rxring),
540305ac5f9Spatrick 	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
541305ac5f9Spatrick 
542305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), 0);
543305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), 0);
544305ac5f9Spatrick 
545305ac5f9Spatrick 	sc->sc_rx_prod = sc->sc_rx_cons = 0;
546305ac5f9Spatrick 	dwqe_fill_rx_ring(sc);
547305ac5f9Spatrick 
548305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring),
549305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_rxring),
550305ac5f9Spatrick 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
551305ac5f9Spatrick 
552305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32);
553305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring));
554305ac5f9Spatrick 
555305ac5f9Spatrick 	/* TODO: re-enable RXQ? */
556305ac5f9Spatrick 
557305ac5f9Spatrick 	splx(s);
558305ac5f9Spatrick }
559305ac5f9Spatrick 
560305ac5f9Spatrick int
561305ac5f9Spatrick dwqe_intr(void *arg)
562305ac5f9Spatrick {
563305ac5f9Spatrick 	struct dwqe_softc *sc = arg;
564305ac5f9Spatrick 	uint32_t reg;
565305ac5f9Spatrick 
566305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_INT_STATUS);
567305ac5f9Spatrick 	dwqe_write(sc, GMAC_INT_STATUS, reg);
568305ac5f9Spatrick 
569305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_STATUS(0));
570305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_STATUS(0), reg);
571305ac5f9Spatrick 
572305ac5f9Spatrick 	if (reg & GMAC_CHAN_STATUS_RI)
573305ac5f9Spatrick 		dwqe_rx_proc(sc);
574305ac5f9Spatrick 
575305ac5f9Spatrick 	if (reg & GMAC_CHAN_STATUS_TI)
576305ac5f9Spatrick 		dwqe_tx_proc(sc);
577305ac5f9Spatrick 
578305ac5f9Spatrick 	return (1);
579305ac5f9Spatrick }
580305ac5f9Spatrick 
581305ac5f9Spatrick void
582305ac5f9Spatrick dwqe_tx_proc(struct dwqe_softc *sc)
583305ac5f9Spatrick {
584305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
585305ac5f9Spatrick 	struct dwqe_desc *txd;
586305ac5f9Spatrick 	struct dwqe_buf *txb;
587305ac5f9Spatrick 	int idx, txfree;
588305ac5f9Spatrick 
589305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 0,
590305ac5f9Spatrick 	    DWQE_DMA_LEN(sc->sc_txring),
591305ac5f9Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
592305ac5f9Spatrick 
593305ac5f9Spatrick 	txfree = 0;
594305ac5f9Spatrick 	while (sc->sc_tx_cons != sc->sc_tx_prod) {
595305ac5f9Spatrick 		idx = sc->sc_tx_cons;
596305ac5f9Spatrick 		KASSERT(idx < DWQE_NTXDESC);
597305ac5f9Spatrick 
598305ac5f9Spatrick 		txd = &sc->sc_txdesc[idx];
599305ac5f9Spatrick 		if (txd->sd_tdes3 & TDES3_OWN)
600305ac5f9Spatrick 			break;
601305ac5f9Spatrick 
602e8974f33Skettenis 		if (txd->sd_tdes3 & TDES3_ES)
603e8974f33Skettenis 			ifp->if_oerrors++;
604e8974f33Skettenis 
605305ac5f9Spatrick 		txb = &sc->sc_txbuf[idx];
606305ac5f9Spatrick 		if (txb->tb_m) {
607305ac5f9Spatrick 			bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0,
608305ac5f9Spatrick 			    txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
609305ac5f9Spatrick 			bus_dmamap_unload(sc->sc_dmat, txb->tb_map);
610305ac5f9Spatrick 
611305ac5f9Spatrick 			m_freem(txb->tb_m);
612305ac5f9Spatrick 			txb->tb_m = NULL;
613305ac5f9Spatrick 		}
614305ac5f9Spatrick 
615305ac5f9Spatrick 		txfree++;
616305ac5f9Spatrick 
617305ac5f9Spatrick 		if (sc->sc_tx_cons == (DWQE_NTXDESC - 1))
618305ac5f9Spatrick 			sc->sc_tx_cons = 0;
619305ac5f9Spatrick 		else
620305ac5f9Spatrick 			sc->sc_tx_cons++;
621305ac5f9Spatrick 
622305ac5f9Spatrick 		txd->sd_tdes3 = 0;
623305ac5f9Spatrick 	}
624305ac5f9Spatrick 
625305ac5f9Spatrick 	if (sc->sc_tx_cons == sc->sc_tx_prod)
626305ac5f9Spatrick 		ifp->if_timer = 0;
627305ac5f9Spatrick 
628305ac5f9Spatrick 	if (txfree) {
629305ac5f9Spatrick 		if (ifq_is_oactive(&ifp->if_snd))
630305ac5f9Spatrick 			ifq_restart(&ifp->if_snd);
631305ac5f9Spatrick 	}
632305ac5f9Spatrick }
633305ac5f9Spatrick 
634305ac5f9Spatrick void
635305ac5f9Spatrick dwqe_rx_proc(struct dwqe_softc *sc)
636305ac5f9Spatrick {
637305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
638305ac5f9Spatrick 	struct dwqe_desc *rxd;
639305ac5f9Spatrick 	struct dwqe_buf *rxb;
640305ac5f9Spatrick 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
641305ac5f9Spatrick 	struct mbuf *m;
642305ac5f9Spatrick 	int idx, len, cnt, put;
643305ac5f9Spatrick 
644305ac5f9Spatrick 	if ((ifp->if_flags & IFF_RUNNING) == 0)
645305ac5f9Spatrick 		return;
646305ac5f9Spatrick 
647305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0,
648305ac5f9Spatrick 	    DWQE_DMA_LEN(sc->sc_rxring),
649305ac5f9Spatrick 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
650305ac5f9Spatrick 
651305ac5f9Spatrick 	cnt = if_rxr_inuse(&sc->sc_rx_ring);
652305ac5f9Spatrick 	put = 0;
653305ac5f9Spatrick 	while (put < cnt) {
654305ac5f9Spatrick 		idx = sc->sc_rx_cons;
655305ac5f9Spatrick 		KASSERT(idx < DWQE_NRXDESC);
656305ac5f9Spatrick 
657305ac5f9Spatrick 		rxd = &sc->sc_rxdesc[idx];
658305ac5f9Spatrick 		if (rxd->sd_tdes3 & RDES3_OWN)
659305ac5f9Spatrick 			break;
660305ac5f9Spatrick 
661305ac5f9Spatrick 		len = rxd->sd_tdes3 & RDES3_LENGTH;
662305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[idx];
663305ac5f9Spatrick 		KASSERT(rxb->tb_m);
664305ac5f9Spatrick 
665305ac5f9Spatrick 		bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0,
666305ac5f9Spatrick 		    len, BUS_DMASYNC_POSTREAD);
667305ac5f9Spatrick 		bus_dmamap_unload(sc->sc_dmat, rxb->tb_map);
668305ac5f9Spatrick 
669b58ef082Skettenis 		m = rxb->tb_m;
670b58ef082Skettenis 		rxb->tb_m = NULL;
671b58ef082Skettenis 
672b58ef082Skettenis 		if (rxd->sd_tdes3 & RDES3_ES) {
673b58ef082Skettenis 			ifp->if_ierrors++;
674b58ef082Skettenis 			m_freem(m);
675b58ef082Skettenis 		} else {
676305ac5f9Spatrick 			/* Strip off CRC. */
677305ac5f9Spatrick 			len -= ETHER_CRC_LEN;
678305ac5f9Spatrick 			KASSERT(len > 0);
679305ac5f9Spatrick 
680305ac5f9Spatrick 			m->m_pkthdr.len = m->m_len = len;
681305ac5f9Spatrick 
682305ac5f9Spatrick 			ml_enqueue(&ml, m);
683b58ef082Skettenis 		}
684305ac5f9Spatrick 
685305ac5f9Spatrick 		put++;
686305ac5f9Spatrick 		if (sc->sc_rx_cons == (DWQE_NRXDESC - 1))
687305ac5f9Spatrick 			sc->sc_rx_cons = 0;
688305ac5f9Spatrick 		else
689305ac5f9Spatrick 			sc->sc_rx_cons++;
690305ac5f9Spatrick 	}
691305ac5f9Spatrick 
692305ac5f9Spatrick 	if_rxr_put(&sc->sc_rx_ring, put);
693305ac5f9Spatrick 	if (ifiq_input(&ifp->if_rcv, &ml))
694305ac5f9Spatrick 		if_rxr_livelocked(&sc->sc_rx_ring);
695305ac5f9Spatrick 
696305ac5f9Spatrick 	dwqe_fill_rx_ring(sc);
697305ac5f9Spatrick 
698305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0,
699305ac5f9Spatrick 	    DWQE_DMA_LEN(sc->sc_rxring),
700305ac5f9Spatrick 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
701305ac5f9Spatrick }
702305ac5f9Spatrick 
703305ac5f9Spatrick void
704305ac5f9Spatrick dwqe_up(struct dwqe_softc *sc)
705305ac5f9Spatrick {
706305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
707305ac5f9Spatrick 	struct dwqe_buf *txb, *rxb;
708*6e9149a4Sstsp 	uint32_t mode, reg, fifosz, tqs, rqs;
709305ac5f9Spatrick 	int i;
710305ac5f9Spatrick 
711305ac5f9Spatrick 	/* Allocate Tx descriptor ring. */
712305ac5f9Spatrick 	sc->sc_txring = dwqe_dmamem_alloc(sc,
713305ac5f9Spatrick 	    DWQE_NTXDESC * sizeof(struct dwqe_desc), 8);
714305ac5f9Spatrick 	sc->sc_txdesc = DWQE_DMA_KVA(sc->sc_txring);
715305ac5f9Spatrick 
716305ac5f9Spatrick 	sc->sc_txbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NTXDESC,
717305ac5f9Spatrick 	    M_DEVBUF, M_WAITOK);
718305ac5f9Spatrick 	for (i = 0; i < DWQE_NTXDESC; i++) {
719305ac5f9Spatrick 		txb = &sc->sc_txbuf[i];
720305ac5f9Spatrick 		bus_dmamap_create(sc->sc_dmat, MCLBYTES, DWQE_NTXSEGS,
721305ac5f9Spatrick 		    MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map);
722305ac5f9Spatrick 		txb->tb_m = NULL;
723305ac5f9Spatrick 	}
724305ac5f9Spatrick 
725305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring),
726305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE);
727305ac5f9Spatrick 
728305ac5f9Spatrick 	sc->sc_tx_prod = sc->sc_tx_cons = 0;
729305ac5f9Spatrick 
730305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_txring) >> 32);
731305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_txring));
732305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_RING_LEN(0), DWQE_NTXDESC - 1);
733305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring));
734305ac5f9Spatrick 
735305ac5f9Spatrick 	/* Allocate  descriptor ring. */
736305ac5f9Spatrick 	sc->sc_rxring = dwqe_dmamem_alloc(sc,
737305ac5f9Spatrick 	    DWQE_NRXDESC * sizeof(struct dwqe_desc), 8);
738305ac5f9Spatrick 	sc->sc_rxdesc = DWQE_DMA_KVA(sc->sc_rxring);
739305ac5f9Spatrick 
740305ac5f9Spatrick 	sc->sc_rxbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NRXDESC,
741305ac5f9Spatrick 	    M_DEVBUF, M_WAITOK);
742305ac5f9Spatrick 
743305ac5f9Spatrick 	for (i = 0; i < DWQE_NRXDESC; i++) {
744305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[i];
745305ac5f9Spatrick 		bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
746305ac5f9Spatrick 		    MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map);
747305ac5f9Spatrick 		rxb->tb_m = NULL;
748305ac5f9Spatrick 	}
749305ac5f9Spatrick 
750305ac5f9Spatrick 	if_rxr_init(&sc->sc_rx_ring, 2, DWQE_NRXDESC);
751305ac5f9Spatrick 
752305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32);
753305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring));
754305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_RING_LEN(0), DWQE_NRXDESC - 1);
755305ac5f9Spatrick 
756305ac5f9Spatrick 	sc->sc_rx_prod = sc->sc_rx_cons = 0;
757305ac5f9Spatrick 	dwqe_fill_rx_ring(sc);
758305ac5f9Spatrick 
759305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring),
760305ac5f9Spatrick 	    0, DWQE_DMA_LEN(sc->sc_rxring),
761305ac5f9Spatrick 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
762305ac5f9Spatrick 
763305ac5f9Spatrick 	dwqe_lladdr_write(sc);
764305ac5f9Spatrick 
765305ac5f9Spatrick 	/* Configure media. */
766305ac5f9Spatrick 	if (LIST_FIRST(&sc->sc_mii.mii_phys))
767305ac5f9Spatrick 		mii_mediachg(&sc->sc_mii);
768305ac5f9Spatrick 
769305ac5f9Spatrick 	/* Program promiscuous mode and multicast filters. */
770305ac5f9Spatrick 	dwqe_iff(sc);
771305ac5f9Spatrick 
772305ac5f9Spatrick 	ifp->if_flags |= IFF_RUNNING;
773305ac5f9Spatrick 	ifq_clr_oactive(&ifp->if_snd);
774305ac5f9Spatrick 
775b97405d6Sstsp 	dwqe_write(sc, GMAC_MAC_1US_TIC_CTR, (sc->sc_clkrate / 1000000) - 1);
776305ac5f9Spatrick 
777305ac5f9Spatrick 	/* Start receive DMA */
778305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0));
779305ac5f9Spatrick 	reg |= GMAC_CHAN_RX_CONTROL_SR;
780305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg);
781305ac5f9Spatrick 
782305ac5f9Spatrick 	/* Start transmit DMA */
783305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0));
784305ac5f9Spatrick 	reg |= GMAC_CHAN_TX_CONTROL_ST;
785305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg);
786305ac5f9Spatrick 
787305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_MTL_CHAN_RX_OP_MODE(0));
788305ac5f9Spatrick 	if (sc->sc_force_thresh_dma_mode) {
789305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RSF;
790305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RTC_MASK;
791305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_RX_OP_MODE_RTC_128;
792305ac5f9Spatrick 	} else {
793305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_RX_OP_MODE_RSF;
794305ac5f9Spatrick 	}
795305ac5f9Spatrick 	mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK;
796*6e9149a4Sstsp 	if (sc->sc_rxfifo_size)
797*6e9149a4Sstsp 		fifosz = sc->sc_rxfifo_size;
798*6e9149a4Sstsp 	else
799*6e9149a4Sstsp 		fifosz = (128 <<
800*6e9149a4Sstsp 		    GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(sc->sc_hw_feature[1]));
801*6e9149a4Sstsp 	rqs = fifosz / 256 - 1;
802*6e9149a4Sstsp 	mode |= (rqs << GMAC_MTL_CHAN_RX_OP_MODE_RQS_SHIFT) &
803*6e9149a4Sstsp 	   GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK;
804*6e9149a4Sstsp 	if (fifosz >= 4096) {
805*6e9149a4Sstsp 		mode |= GMAC_MTL_CHAN_RX_OP_MODE_EHFC;
806*6e9149a4Sstsp 		mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RFD_MASK;
807*6e9149a4Sstsp 		mode |= 0x3 << GMAC_MTL_CHAN_RX_OP_MODE_RFD_SHIFT;
808*6e9149a4Sstsp 		mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RFA_MASK;
809*6e9149a4Sstsp 		mode |= 0x1 << GMAC_MTL_CHAN_RX_OP_MODE_RFA_SHIFT;
810*6e9149a4Sstsp 	}
811305ac5f9Spatrick 	dwqe_write(sc, GMAC_MTL_CHAN_RX_OP_MODE(0), mode);
812305ac5f9Spatrick 
813305ac5f9Spatrick 	mode = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0));
814305ac5f9Spatrick 	if (sc->sc_force_thresh_dma_mode) {
815305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TSF;
816305ac5f9Spatrick 		mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TTC_MASK;
817e8974f33Skettenis 		mode |= GMAC_MTL_CHAN_TX_OP_MODE_TTC_512;
818305ac5f9Spatrick 	} else {
819305ac5f9Spatrick 		mode |= GMAC_MTL_CHAN_TX_OP_MODE_TSF;
820305ac5f9Spatrick 	}
821305ac5f9Spatrick 	mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TXQEN_MASK;
822305ac5f9Spatrick 	mode |= GMAC_MTL_CHAN_TX_OP_MODE_TXQEN;
823305ac5f9Spatrick 	mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK;
824*6e9149a4Sstsp 	if (sc->sc_txfifo_size)
825*6e9149a4Sstsp 		fifosz = sc->sc_txfifo_size;
826*6e9149a4Sstsp 	else
827*6e9149a4Sstsp 		fifosz = (128 <<
828*6e9149a4Sstsp 		    GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(sc->sc_hw_feature[1]));
829*6e9149a4Sstsp 	tqs = (fifosz / 256) - 1;
830*6e9149a4Sstsp 	mode |= (tqs << GMAC_MTL_CHAN_TX_OP_MODE_TQS_SHIFT) &
831*6e9149a4Sstsp 	    GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK;
832305ac5f9Spatrick 	dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), mode);
833305ac5f9Spatrick 
834305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_QX_TX_FLOW_CTRL(0));
835305ac5f9Spatrick 	reg |= 0xffffU << GMAC_QX_TX_FLOW_CTRL_PT_SHIFT;
836305ac5f9Spatrick 	reg |= GMAC_QX_TX_FLOW_CTRL_TFE;
837305ac5f9Spatrick 	dwqe_write(sc, GMAC_QX_TX_FLOW_CTRL(0), reg);
838305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_RX_FLOW_CTRL);
839305ac5f9Spatrick 	reg |= GMAC_RX_FLOW_CTRL_RFE;
840305ac5f9Spatrick 	dwqe_write(sc, GMAC_RX_FLOW_CTRL, reg);
841305ac5f9Spatrick 
842305ac5f9Spatrick 	dwqe_write(sc, GMAC_RXQ_CTRL0, GMAC_RXQ_CTRL0_DCB_QUEUE_EN(0));
843305ac5f9Spatrick 
844305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, dwqe_read(sc, GMAC_MAC_CONF) |
845305ac5f9Spatrick 	    GMAC_MAC_CONF_BE | GMAC_MAC_CONF_JD | GMAC_MAC_CONF_JE |
846305ac5f9Spatrick 	    GMAC_MAC_CONF_DCRS | GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE);
847305ac5f9Spatrick 
848305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_INTR_ENA(0),
849305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_NIE |
850305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_AIE |
851305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_FBE |
852305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_RIE |
853305ac5f9Spatrick 	    GMAC_CHAN_INTR_ENA_TIE);
854305ac5f9Spatrick 
85545f5f3c8Sdlg 	if (!sc->sc_fixed_link)
85647707f8eSdlg 		timeout_add_sec(&sc->sc_phy_tick, 1);
857305ac5f9Spatrick }
858305ac5f9Spatrick 
859305ac5f9Spatrick void
860305ac5f9Spatrick dwqe_down(struct dwqe_softc *sc)
861305ac5f9Spatrick {
862305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
863305ac5f9Spatrick 	struct dwqe_buf *txb, *rxb;
864305ac5f9Spatrick 	uint32_t reg;
865305ac5f9Spatrick 	int i;
866305ac5f9Spatrick 
867305ac5f9Spatrick 	timeout_del(&sc->sc_rxto);
86845f5f3c8Sdlg 	if (!sc->sc_fixed_link)
86947707f8eSdlg 		timeout_del(&sc->sc_phy_tick);
870305ac5f9Spatrick 
871305ac5f9Spatrick 	ifp->if_flags &= ~IFF_RUNNING;
872305ac5f9Spatrick 	ifq_clr_oactive(&ifp->if_snd);
873305ac5f9Spatrick 	ifp->if_timer = 0;
874305ac5f9Spatrick 
875305ac5f9Spatrick 	/* Disable receiver */
876305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_MAC_CONF);
877305ac5f9Spatrick 	reg &= ~GMAC_MAC_CONF_RE;
878305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, reg);
879305ac5f9Spatrick 
880305ac5f9Spatrick 	/* Stop receive DMA */
881305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0));
882305ac5f9Spatrick 	reg &= ~GMAC_CHAN_RX_CONTROL_SR;
883305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg);
884305ac5f9Spatrick 
885305ac5f9Spatrick 	/* Stop transmit DMA */
886305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0));
887305ac5f9Spatrick 	reg &= ~GMAC_CHAN_TX_CONTROL_ST;
888305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg);
889305ac5f9Spatrick 
890305ac5f9Spatrick 	/* Flush data in the TX FIFO */
891305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0));
892305ac5f9Spatrick 	reg |= GMAC_MTL_CHAN_TX_OP_MODE_FTQ;
893305ac5f9Spatrick 	dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), reg);
894305ac5f9Spatrick 	/* Wait for flush to complete */
895305ac5f9Spatrick 	for (i = 10000; i > 0; i--) {
896305ac5f9Spatrick 		reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0));
897305ac5f9Spatrick 		if ((reg & GMAC_MTL_CHAN_TX_OP_MODE_FTQ) == 0)
898305ac5f9Spatrick 			break;
899305ac5f9Spatrick 		delay(1);
900305ac5f9Spatrick 	}
901305ac5f9Spatrick 	if (i == 0) {
902305ac5f9Spatrick 		printf("%s: timeout flushing TX queue\n",
903305ac5f9Spatrick 		    sc->sc_dev.dv_xname);
904305ac5f9Spatrick 	}
905305ac5f9Spatrick 
906305ac5f9Spatrick 	/* Disable transmitter */
907305ac5f9Spatrick 	reg = dwqe_read(sc, GMAC_MAC_CONF);
908305ac5f9Spatrick 	reg &= ~GMAC_MAC_CONF_TE;
909305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_CONF, reg);
910305ac5f9Spatrick 
911305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0);
912305ac5f9Spatrick 
913305ac5f9Spatrick 	intr_barrier(sc->sc_ih);
914305ac5f9Spatrick 	ifq_barrier(&ifp->if_snd);
915305ac5f9Spatrick 
916305ac5f9Spatrick 	for (i = 0; i < DWQE_NTXDESC; i++) {
917305ac5f9Spatrick 		txb = &sc->sc_txbuf[i];
918305ac5f9Spatrick 		if (txb->tb_m) {
919305ac5f9Spatrick 			bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0,
920305ac5f9Spatrick 			    txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
921305ac5f9Spatrick 			bus_dmamap_unload(sc->sc_dmat, txb->tb_map);
922305ac5f9Spatrick 			m_freem(txb->tb_m);
923305ac5f9Spatrick 		}
924305ac5f9Spatrick 		bus_dmamap_destroy(sc->sc_dmat, txb->tb_map);
925305ac5f9Spatrick 	}
926305ac5f9Spatrick 
927305ac5f9Spatrick 	dwqe_dmamem_free(sc, sc->sc_txring);
928305ac5f9Spatrick 	free(sc->sc_txbuf, M_DEVBUF, 0);
929305ac5f9Spatrick 
930305ac5f9Spatrick 	for (i = 0; i < DWQE_NRXDESC; i++) {
931305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[i];
932305ac5f9Spatrick 		if (rxb->tb_m) {
933305ac5f9Spatrick 			bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0,
934305ac5f9Spatrick 			    rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
935305ac5f9Spatrick 			bus_dmamap_unload(sc->sc_dmat, rxb->tb_map);
936305ac5f9Spatrick 			m_freem(rxb->tb_m);
937305ac5f9Spatrick 		}
938305ac5f9Spatrick 		bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map);
939305ac5f9Spatrick 	}
940305ac5f9Spatrick 
941305ac5f9Spatrick 	dwqe_dmamem_free(sc, sc->sc_rxring);
942305ac5f9Spatrick 	free(sc->sc_rxbuf, M_DEVBUF, 0);
943305ac5f9Spatrick }
944305ac5f9Spatrick 
945305ac5f9Spatrick /* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */
946305ac5f9Spatrick static uint32_t
947305ac5f9Spatrick bitrev32(uint32_t x)
948305ac5f9Spatrick {
949305ac5f9Spatrick 	x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
950305ac5f9Spatrick 	x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
951305ac5f9Spatrick 	x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
952305ac5f9Spatrick 	x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
953305ac5f9Spatrick 
954305ac5f9Spatrick 	return (x >> 16) | (x << 16);
955305ac5f9Spatrick }
956305ac5f9Spatrick 
957305ac5f9Spatrick void
958305ac5f9Spatrick dwqe_iff(struct dwqe_softc *sc)
959305ac5f9Spatrick {
960305ac5f9Spatrick 	struct arpcom *ac = &sc->sc_ac;
961305ac5f9Spatrick 	struct ifnet *ifp = &sc->sc_ac.ac_if;
962305ac5f9Spatrick 	struct ether_multi *enm;
963305ac5f9Spatrick 	struct ether_multistep step;
964305ac5f9Spatrick 	uint32_t crc, hash[2], hashbit, hashreg;
965305ac5f9Spatrick 	uint32_t reg;
966305ac5f9Spatrick 
967305ac5f9Spatrick 	reg = 0;
968305ac5f9Spatrick 
969305ac5f9Spatrick 	ifp->if_flags &= ~IFF_ALLMULTI;
970305ac5f9Spatrick 	bzero(hash, sizeof(hash));
971305ac5f9Spatrick 	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
972305ac5f9Spatrick 		ifp->if_flags |= IFF_ALLMULTI;
973305ac5f9Spatrick 		reg |= GMAC_MAC_PACKET_FILTER_PM;
974305ac5f9Spatrick 		if (ifp->if_flags & IFF_PROMISC)
975305ac5f9Spatrick 			reg |= GMAC_MAC_PACKET_FILTER_PR |
976305ac5f9Spatrick 			    GMAC_MAC_PACKET_FILTER_PCF_ALL;
977305ac5f9Spatrick 	} else {
978305ac5f9Spatrick 		reg |= GMAC_MAC_PACKET_FILTER_HMC;
979305ac5f9Spatrick 		ETHER_FIRST_MULTI(step, ac, enm);
980305ac5f9Spatrick 		while (enm != NULL) {
981305ac5f9Spatrick 			crc = ether_crc32_le(enm->enm_addrlo,
982305ac5f9Spatrick 			    ETHER_ADDR_LEN) & 0x7f;
983305ac5f9Spatrick 
984305ac5f9Spatrick 			crc = bitrev32(~crc) >> 26;
985305ac5f9Spatrick 			hashreg = (crc >> 5);
986305ac5f9Spatrick 			hashbit = (crc & 0x1f);
987305ac5f9Spatrick 			hash[hashreg] |= (1 << hashbit);
988305ac5f9Spatrick 
989305ac5f9Spatrick 			ETHER_NEXT_MULTI(step, enm);
990305ac5f9Spatrick 		}
991305ac5f9Spatrick 	}
992305ac5f9Spatrick 
993305ac5f9Spatrick 	dwqe_lladdr_write(sc);
994305ac5f9Spatrick 
995305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_HASH_TAB_REG0, hash[0]);
996305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_HASH_TAB_REG1, hash[1]);
997305ac5f9Spatrick 
998305ac5f9Spatrick 	dwqe_write(sc, GMAC_MAC_PACKET_FILTER, reg);
999305ac5f9Spatrick }
1000305ac5f9Spatrick 
1001305ac5f9Spatrick int
1002305ac5f9Spatrick dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used)
1003305ac5f9Spatrick {
1004305ac5f9Spatrick 	struct dwqe_desc *txd, *txd_start;
1005305ac5f9Spatrick 	bus_dmamap_t map;
1006305ac5f9Spatrick 	int cur, frag, i;
1007305ac5f9Spatrick 
1008305ac5f9Spatrick 	cur = frag = *idx;
1009305ac5f9Spatrick 	map = sc->sc_txbuf[cur].tb_map;
1010305ac5f9Spatrick 
1011305ac5f9Spatrick 	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) {
1012305ac5f9Spatrick 		if (m_defrag(m, M_DONTWAIT))
1013305ac5f9Spatrick 			return (EFBIG);
1014305ac5f9Spatrick 		if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT))
1015305ac5f9Spatrick 			return (EFBIG);
1016305ac5f9Spatrick 	}
1017305ac5f9Spatrick 
1018305ac5f9Spatrick 	/* Sync the DMA map. */
1019305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1020305ac5f9Spatrick 	    BUS_DMASYNC_PREWRITE);
1021305ac5f9Spatrick 
1022305ac5f9Spatrick 	txd = txd_start = &sc->sc_txdesc[frag];
1023305ac5f9Spatrick 	for (i = 0; i < map->dm_nsegs; i++) {
1024305ac5f9Spatrick 		/* TODO: check for 32-bit vs 64-bit support */
1025305ac5f9Spatrick 		KASSERT((map->dm_segs[i].ds_addr >> 32) == 0);
1026305ac5f9Spatrick 
1027305ac5f9Spatrick 		txd->sd_tdes0 = (uint32_t)map->dm_segs[i].ds_addr;
1028305ac5f9Spatrick 		txd->sd_tdes1 = (uint32_t)(map->dm_segs[i].ds_addr >> 32);
1029305ac5f9Spatrick 		txd->sd_tdes2 = map->dm_segs[i].ds_len;
1030305ac5f9Spatrick 		txd->sd_tdes3 = m->m_pkthdr.len;
1031305ac5f9Spatrick 		if (i == 0)
1032305ac5f9Spatrick 			txd->sd_tdes3 |= TDES3_FS;
1033305ac5f9Spatrick 		if (i == (map->dm_nsegs - 1)) {
1034305ac5f9Spatrick 			txd->sd_tdes2 |= TDES2_IC;
1035305ac5f9Spatrick 			txd->sd_tdes3 |= TDES3_LS;
1036305ac5f9Spatrick 		}
1037305ac5f9Spatrick 		if (i != 0)
1038305ac5f9Spatrick 			txd->sd_tdes3 |= TDES3_OWN;
1039305ac5f9Spatrick 
1040305ac5f9Spatrick 		bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring),
1041305ac5f9Spatrick 		    frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE);
1042305ac5f9Spatrick 
1043305ac5f9Spatrick 		cur = frag;
1044305ac5f9Spatrick 		if (frag == (DWQE_NTXDESC - 1)) {
1045305ac5f9Spatrick 			txd = &sc->sc_txdesc[0];
1046305ac5f9Spatrick 			frag = 0;
1047305ac5f9Spatrick 		} else {
1048305ac5f9Spatrick 			txd++;
1049305ac5f9Spatrick 			frag++;
1050305ac5f9Spatrick 		}
1051305ac5f9Spatrick 		KASSERT(frag != sc->sc_tx_cons);
1052305ac5f9Spatrick 	}
1053305ac5f9Spatrick 
1054305ac5f9Spatrick 	txd_start->sd_tdes3 |= TDES3_OWN;
1055305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring),
1056305ac5f9Spatrick 	    *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE);
1057305ac5f9Spatrick 
1058305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring) +
10594fa84378Skettenis 	    frag * sizeof(*txd));
1060305ac5f9Spatrick 
1061305ac5f9Spatrick 	KASSERT(sc->sc_txbuf[cur].tb_m == NULL);
1062305ac5f9Spatrick 	sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map;
1063305ac5f9Spatrick 	sc->sc_txbuf[cur].tb_map = map;
1064305ac5f9Spatrick 	sc->sc_txbuf[cur].tb_m = m;
1065305ac5f9Spatrick 
1066305ac5f9Spatrick 	*idx = frag;
1067305ac5f9Spatrick 	*used += map->dm_nsegs;
1068305ac5f9Spatrick 
1069305ac5f9Spatrick 	return (0);
1070305ac5f9Spatrick }
1071305ac5f9Spatrick 
1072305ac5f9Spatrick void
1073305ac5f9Spatrick dwqe_reset(struct dwqe_softc *sc)
1074305ac5f9Spatrick {
1075305ac5f9Spatrick 	int n;
1076305ac5f9Spatrick 
1077305ac5f9Spatrick 	dwqe_write(sc, GMAC_BUS_MODE, dwqe_read(sc, GMAC_BUS_MODE) |
1078305ac5f9Spatrick 	    GMAC_BUS_MODE_SWR);
1079305ac5f9Spatrick 
1080305ac5f9Spatrick 	for (n = 0; n < 30000; n++) {
1081305ac5f9Spatrick 		if ((dwqe_read(sc, GMAC_BUS_MODE) &
1082305ac5f9Spatrick 		    GMAC_BUS_MODE_SWR) == 0)
1083305ac5f9Spatrick 			return;
1084305ac5f9Spatrick 		delay(10);
1085305ac5f9Spatrick 	}
1086305ac5f9Spatrick 
1087305ac5f9Spatrick 	printf("%s: reset timeout\n", sc->sc_dev.dv_xname);
1088305ac5f9Spatrick }
1089305ac5f9Spatrick 
1090305ac5f9Spatrick struct dwqe_dmamem *
1091305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *sc, bus_size_t size, bus_size_t align)
1092305ac5f9Spatrick {
1093305ac5f9Spatrick 	struct dwqe_dmamem *tdm;
1094305ac5f9Spatrick 	int nsegs;
1095305ac5f9Spatrick 
1096305ac5f9Spatrick 	tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO);
1097305ac5f9Spatrick 	tdm->tdm_size = size;
1098305ac5f9Spatrick 
1099305ac5f9Spatrick 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1100305ac5f9Spatrick 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0)
1101305ac5f9Spatrick 		goto tdmfree;
1102305ac5f9Spatrick 
1103305ac5f9Spatrick 	if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1,
1104305ac5f9Spatrick 	    &nsegs, BUS_DMA_WAITOK) != 0)
1105305ac5f9Spatrick 		goto destroy;
1106305ac5f9Spatrick 
1107305ac5f9Spatrick 	if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size,
1108305ac5f9Spatrick 	    &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0)
1109305ac5f9Spatrick 		goto free;
1110305ac5f9Spatrick 
1111305ac5f9Spatrick 	if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size,
1112305ac5f9Spatrick 	    NULL, BUS_DMA_WAITOK) != 0)
1113305ac5f9Spatrick 		goto unmap;
1114305ac5f9Spatrick 
1115305ac5f9Spatrick 	bzero(tdm->tdm_kva, size);
1116305ac5f9Spatrick 
1117305ac5f9Spatrick 	return (tdm);
1118305ac5f9Spatrick 
1119305ac5f9Spatrick unmap:
1120305ac5f9Spatrick 	bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size);
1121305ac5f9Spatrick free:
1122305ac5f9Spatrick 	bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1);
1123305ac5f9Spatrick destroy:
1124305ac5f9Spatrick 	bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map);
1125305ac5f9Spatrick tdmfree:
1126305ac5f9Spatrick 	free(tdm, M_DEVBUF, 0);
1127305ac5f9Spatrick 
1128305ac5f9Spatrick 	return (NULL);
1129305ac5f9Spatrick }
1130305ac5f9Spatrick 
1131305ac5f9Spatrick void
1132305ac5f9Spatrick dwqe_dmamem_free(struct dwqe_softc *sc, struct dwqe_dmamem *tdm)
1133305ac5f9Spatrick {
1134305ac5f9Spatrick 	bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size);
1135305ac5f9Spatrick 	bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1);
1136305ac5f9Spatrick 	bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map);
1137305ac5f9Spatrick 	free(tdm, M_DEVBUF, 0);
1138305ac5f9Spatrick }
1139305ac5f9Spatrick 
1140305ac5f9Spatrick struct mbuf *
1141305ac5f9Spatrick dwqe_alloc_mbuf(struct dwqe_softc *sc, bus_dmamap_t map)
1142305ac5f9Spatrick {
1143305ac5f9Spatrick 	struct mbuf *m = NULL;
1144305ac5f9Spatrick 
1145305ac5f9Spatrick 	m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES);
1146305ac5f9Spatrick 	if (!m)
1147305ac5f9Spatrick 		return (NULL);
1148305ac5f9Spatrick 	m->m_len = m->m_pkthdr.len = MCLBYTES;
1149305ac5f9Spatrick 	m_adj(m, ETHER_ALIGN);
1150305ac5f9Spatrick 
1151305ac5f9Spatrick 	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) {
1152305ac5f9Spatrick 		printf("%s: could not load mbuf DMA map", DEVNAME(sc));
1153305ac5f9Spatrick 		m_freem(m);
1154305ac5f9Spatrick 		return (NULL);
1155305ac5f9Spatrick 	}
1156305ac5f9Spatrick 
1157305ac5f9Spatrick 	bus_dmamap_sync(sc->sc_dmat, map, 0,
1158305ac5f9Spatrick 	    m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
1159305ac5f9Spatrick 
1160305ac5f9Spatrick 	return (m);
1161305ac5f9Spatrick }
1162305ac5f9Spatrick 
1163305ac5f9Spatrick void
1164305ac5f9Spatrick dwqe_fill_rx_ring(struct dwqe_softc *sc)
1165305ac5f9Spatrick {
1166305ac5f9Spatrick 	struct dwqe_desc *rxd;
1167305ac5f9Spatrick 	struct dwqe_buf *rxb;
1168305ac5f9Spatrick 	u_int slots;
1169305ac5f9Spatrick 
1170305ac5f9Spatrick 	for (slots = if_rxr_get(&sc->sc_rx_ring, DWQE_NRXDESC);
1171305ac5f9Spatrick 	    slots > 0; slots--) {
1172305ac5f9Spatrick 		rxb = &sc->sc_rxbuf[sc->sc_rx_prod];
1173305ac5f9Spatrick 		rxb->tb_m = dwqe_alloc_mbuf(sc, rxb->tb_map);
1174305ac5f9Spatrick 		if (rxb->tb_m == NULL)
1175305ac5f9Spatrick 			break;
1176305ac5f9Spatrick 
1177305ac5f9Spatrick 		/* TODO: check for 32-bit vs 64-bit support */
11784fa84378Skettenis 		KASSERT((rxb->tb_map->dm_segs[0].ds_addr >> 32) == 0);
1179305ac5f9Spatrick 
1180305ac5f9Spatrick 		rxd = &sc->sc_rxdesc[sc->sc_rx_prod];
11814fa84378Skettenis 		rxd->sd_tdes0 = (uint32_t)rxb->tb_map->dm_segs[0].ds_addr;
11824fa84378Skettenis 		rxd->sd_tdes1 = (uint32_t)(rxb->tb_map->dm_segs[0].ds_addr >> 32);
1183305ac5f9Spatrick 		rxd->sd_tdes2 = 0;
1184305ac5f9Spatrick 		rxd->sd_tdes3 = RDES3_OWN | RDES3_IC | RDES3_BUF1V;
1185305ac5f9Spatrick 
1186305ac5f9Spatrick 		if (sc->sc_rx_prod == (DWQE_NRXDESC - 1))
1187305ac5f9Spatrick 			sc->sc_rx_prod = 0;
1188305ac5f9Spatrick 		else
1189305ac5f9Spatrick 			sc->sc_rx_prod++;
1190305ac5f9Spatrick 	}
1191305ac5f9Spatrick 	if_rxr_put(&sc->sc_rx_ring, slots);
1192305ac5f9Spatrick 
1193305ac5f9Spatrick 	dwqe_write(sc, GMAC_CHAN_RX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring) +
1194305ac5f9Spatrick 	    sc->sc_rx_prod * sizeof(*rxd));
1195305ac5f9Spatrick 
1196305ac5f9Spatrick 	if (if_rxr_inuse(&sc->sc_rx_ring) == 0)
1197305ac5f9Spatrick 		timeout_add(&sc->sc_rxto, 1);
1198305ac5f9Spatrick }
1199