xref: /freebsd/sys/dev/dwc/dwc1000_dma.c (revision afa0f66e81ccd6a946133bb9aceaf1fe59370431)
1972adf0fSEmmanuel Vadot /*-
2972adf0fSEmmanuel Vadot  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3972adf0fSEmmanuel Vadot  *
4972adf0fSEmmanuel Vadot  * This software was developed by SRI International and the University of
5972adf0fSEmmanuel Vadot  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
6972adf0fSEmmanuel Vadot  * ("CTSRD"), as part of the DARPA CRASH research programme.
7972adf0fSEmmanuel Vadot  *
8972adf0fSEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
9972adf0fSEmmanuel Vadot  * modification, are permitted provided that the following conditions
10972adf0fSEmmanuel Vadot  * are met:
11972adf0fSEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
12972adf0fSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
13972adf0fSEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
14972adf0fSEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
15972adf0fSEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
16972adf0fSEmmanuel Vadot  *
17972adf0fSEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18972adf0fSEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19972adf0fSEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20972adf0fSEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21972adf0fSEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22972adf0fSEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23972adf0fSEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24972adf0fSEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25972adf0fSEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26972adf0fSEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27972adf0fSEmmanuel Vadot  * SUCH DAMAGE.
28972adf0fSEmmanuel Vadot  */
29972adf0fSEmmanuel Vadot 
30972adf0fSEmmanuel Vadot #include <sys/cdefs.h>
31972adf0fSEmmanuel Vadot #include <sys/param.h>
32972adf0fSEmmanuel Vadot #include <sys/systm.h>
33972adf0fSEmmanuel Vadot #include <sys/bus.h>
34972adf0fSEmmanuel Vadot #include <sys/kernel.h>
35972adf0fSEmmanuel Vadot #include <sys/lock.h>
36972adf0fSEmmanuel Vadot #include <sys/malloc.h>
37972adf0fSEmmanuel Vadot #include <sys/mbuf.h>
38972adf0fSEmmanuel Vadot #include <sys/module.h>
39972adf0fSEmmanuel Vadot #include <sys/mutex.h>
40972adf0fSEmmanuel Vadot #include <sys/rman.h>
41972adf0fSEmmanuel Vadot #include <sys/socket.h>
42972adf0fSEmmanuel Vadot 
43972adf0fSEmmanuel Vadot #include <net/bpf.h>
44972adf0fSEmmanuel Vadot #include <net/if.h>
45972adf0fSEmmanuel Vadot #include <net/ethernet.h>
46972adf0fSEmmanuel Vadot #include <net/if_dl.h>
47972adf0fSEmmanuel Vadot #include <net/if_media.h>
48972adf0fSEmmanuel Vadot #include <net/if_types.h>
49972adf0fSEmmanuel Vadot #include <net/if_var.h>
50972adf0fSEmmanuel Vadot 
51972adf0fSEmmanuel Vadot #include <machine/bus.h>
52972adf0fSEmmanuel Vadot 
53972adf0fSEmmanuel Vadot #include <dev/extres/clk/clk.h>
54972adf0fSEmmanuel Vadot #include <dev/extres/hwreset/hwreset.h>
55972adf0fSEmmanuel Vadot 
56972adf0fSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
57972adf0fSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
58972adf0fSEmmanuel Vadot 
59972adf0fSEmmanuel Vadot #include <dev/dwc/if_dwcvar.h>
60972adf0fSEmmanuel Vadot #include <dev/dwc/dwc1000_reg.h>
61972adf0fSEmmanuel Vadot #include <dev/dwc/dwc1000_dma.h>
62972adf0fSEmmanuel Vadot 
63*afa0f66eSEmmanuel Vadot #define	WATCHDOG_TIMEOUT_SECS	5
64*afa0f66eSEmmanuel Vadot 
65*afa0f66eSEmmanuel Vadot static inline uint32_t
66*afa0f66eSEmmanuel Vadot next_txidx(struct dwc_softc *sc, uint32_t curidx)
67*afa0f66eSEmmanuel Vadot {
68*afa0f66eSEmmanuel Vadot 
69*afa0f66eSEmmanuel Vadot 	return ((curidx + 1) % TX_DESC_COUNT);
70*afa0f66eSEmmanuel Vadot }
71*afa0f66eSEmmanuel Vadot 
72972adf0fSEmmanuel Vadot static inline uint32_t
73972adf0fSEmmanuel Vadot next_rxidx(struct dwc_softc *sc, uint32_t curidx)
74972adf0fSEmmanuel Vadot {
75972adf0fSEmmanuel Vadot 
76972adf0fSEmmanuel Vadot 	return ((curidx + 1) % RX_DESC_COUNT);
77972adf0fSEmmanuel Vadot }
78972adf0fSEmmanuel Vadot 
79972adf0fSEmmanuel Vadot static void
80972adf0fSEmmanuel Vadot dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
81972adf0fSEmmanuel Vadot {
82972adf0fSEmmanuel Vadot 
83972adf0fSEmmanuel Vadot 	if (error != 0)
84972adf0fSEmmanuel Vadot 		return;
85972adf0fSEmmanuel Vadot 	*(bus_addr_t *)arg = segs[0].ds_addr;
86972adf0fSEmmanuel Vadot }
87972adf0fSEmmanuel Vadot 
88972adf0fSEmmanuel Vadot inline static void
89972adf0fSEmmanuel Vadot dwc_set_owner(struct dwc_softc *sc, int idx)
90972adf0fSEmmanuel Vadot {
91972adf0fSEmmanuel Vadot 	wmb();
92972adf0fSEmmanuel Vadot 	sc->txdesc_ring[idx].desc0 |= TDESC0_OWN;
93972adf0fSEmmanuel Vadot 	wmb();
94972adf0fSEmmanuel Vadot }
95972adf0fSEmmanuel Vadot 
96972adf0fSEmmanuel Vadot inline static void
97972adf0fSEmmanuel Vadot dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr,
98972adf0fSEmmanuel Vadot   uint32_t len, uint32_t flags, bool first, bool last)
99972adf0fSEmmanuel Vadot {
100972adf0fSEmmanuel Vadot 	uint32_t desc0, desc1;
101972adf0fSEmmanuel Vadot 
102972adf0fSEmmanuel Vadot 	/* Addr/len 0 means we're clearing the descriptor after xmit done. */
103972adf0fSEmmanuel Vadot 	if (paddr == 0 || len == 0) {
104972adf0fSEmmanuel Vadot 		desc0 = 0;
105972adf0fSEmmanuel Vadot 		desc1 = 0;
106972adf0fSEmmanuel Vadot 		--sc->tx_desccount;
107972adf0fSEmmanuel Vadot 	} else {
108972adf0fSEmmanuel Vadot 		if (sc->mactype != DWC_GMAC_EXT_DESC) {
109972adf0fSEmmanuel Vadot 			desc0 = 0;
110972adf0fSEmmanuel Vadot 			desc1 = NTDESC1_TCH | len | flags;
111972adf0fSEmmanuel Vadot 			if (first)
112972adf0fSEmmanuel Vadot 				desc1 |=  NTDESC1_FS;
113972adf0fSEmmanuel Vadot 			if (last)
114972adf0fSEmmanuel Vadot 				desc1 |= NTDESC1_LS | NTDESC1_IC;
115972adf0fSEmmanuel Vadot 		} else {
116972adf0fSEmmanuel Vadot 			desc0 = ETDESC0_TCH | flags;
117972adf0fSEmmanuel Vadot 			if (first)
118972adf0fSEmmanuel Vadot 				desc0 |= ETDESC0_FS;
119972adf0fSEmmanuel Vadot 			if (last)
120972adf0fSEmmanuel Vadot 				desc0 |= ETDESC0_LS | ETDESC0_IC;
121972adf0fSEmmanuel Vadot 			desc1 = len;
122972adf0fSEmmanuel Vadot 		}
123972adf0fSEmmanuel Vadot 		++sc->tx_desccount;
124972adf0fSEmmanuel Vadot 	}
125972adf0fSEmmanuel Vadot 
126972adf0fSEmmanuel Vadot 	sc->txdesc_ring[idx].addr1 = (uint32_t)(paddr);
127972adf0fSEmmanuel Vadot 	sc->txdesc_ring[idx].desc0 = desc0;
128972adf0fSEmmanuel Vadot 	sc->txdesc_ring[idx].desc1 = desc1;
129972adf0fSEmmanuel Vadot }
130972adf0fSEmmanuel Vadot 
131972adf0fSEmmanuel Vadot inline static uint32_t
132972adf0fSEmmanuel Vadot dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr)
133972adf0fSEmmanuel Vadot {
134972adf0fSEmmanuel Vadot 	uint32_t nidx;
135972adf0fSEmmanuel Vadot 
136972adf0fSEmmanuel Vadot 	sc->rxdesc_ring[idx].addr1 = (uint32_t)paddr;
137972adf0fSEmmanuel Vadot 	nidx = next_rxidx(sc, idx);
138972adf0fSEmmanuel Vadot 	sc->rxdesc_ring[idx].addr2 = sc->rxdesc_ring_paddr +
139972adf0fSEmmanuel Vadot 	    (nidx * sizeof(struct dwc_hwdesc));
140972adf0fSEmmanuel Vadot 	if (sc->mactype != DWC_GMAC_EXT_DESC)
141972adf0fSEmmanuel Vadot 		sc->rxdesc_ring[idx].desc1 = NRDESC1_RCH |
142972adf0fSEmmanuel Vadot 		    MIN(MCLBYTES, NRDESC1_RBS1_MASK);
143972adf0fSEmmanuel Vadot 	else
144972adf0fSEmmanuel Vadot 		sc->rxdesc_ring[idx].desc1 = ERDESC1_RCH |
145972adf0fSEmmanuel Vadot 		    MIN(MCLBYTES, ERDESC1_RBS1_MASK);
146972adf0fSEmmanuel Vadot 
147972adf0fSEmmanuel Vadot 	wmb();
148972adf0fSEmmanuel Vadot 	sc->rxdesc_ring[idx].desc0 = RDESC0_OWN;
149972adf0fSEmmanuel Vadot 	wmb();
150972adf0fSEmmanuel Vadot 	return (nidx);
151972adf0fSEmmanuel Vadot }
152972adf0fSEmmanuel Vadot 
153972adf0fSEmmanuel Vadot int
154972adf0fSEmmanuel Vadot dma1000_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp)
155972adf0fSEmmanuel Vadot {
156972adf0fSEmmanuel Vadot 	struct bus_dma_segment segs[TX_MAP_MAX_SEGS];
157972adf0fSEmmanuel Vadot 	int error, nsegs;
158972adf0fSEmmanuel Vadot 	struct mbuf * m;
159972adf0fSEmmanuel Vadot 	uint32_t flags = 0;
160972adf0fSEmmanuel Vadot 	int i;
161972adf0fSEmmanuel Vadot 	int first, last;
162972adf0fSEmmanuel Vadot 
163972adf0fSEmmanuel Vadot 	error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
164972adf0fSEmmanuel Vadot 	    *mp, segs, &nsegs, 0);
165972adf0fSEmmanuel Vadot 	if (error == EFBIG) {
166972adf0fSEmmanuel Vadot 		/*
167972adf0fSEmmanuel Vadot 		 * The map may be partially mapped from the first call.
168972adf0fSEmmanuel Vadot 		 * Make sure to reset it.
169972adf0fSEmmanuel Vadot 		 */
170972adf0fSEmmanuel Vadot 		bus_dmamap_unload(sc->txbuf_tag, sc->txbuf_map[idx].map);
171972adf0fSEmmanuel Vadot 		if ((m = m_defrag(*mp, M_NOWAIT)) == NULL)
172972adf0fSEmmanuel Vadot 			return (ENOMEM);
173972adf0fSEmmanuel Vadot 		*mp = m;
174972adf0fSEmmanuel Vadot 		error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
175972adf0fSEmmanuel Vadot 		    *mp, segs, &nsegs, 0);
176972adf0fSEmmanuel Vadot 	}
177972adf0fSEmmanuel Vadot 	if (error != 0)
178972adf0fSEmmanuel Vadot 		return (ENOMEM);
179972adf0fSEmmanuel Vadot 
180972adf0fSEmmanuel Vadot 	if (sc->tx_desccount + nsegs > TX_DESC_COUNT) {
181972adf0fSEmmanuel Vadot 		bus_dmamap_unload(sc->txbuf_tag, sc->txbuf_map[idx].map);
182972adf0fSEmmanuel Vadot 		return (ENOMEM);
183972adf0fSEmmanuel Vadot 	}
184972adf0fSEmmanuel Vadot 
185972adf0fSEmmanuel Vadot 	m = *mp;
186972adf0fSEmmanuel Vadot 
187972adf0fSEmmanuel Vadot 	if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) {
188972adf0fSEmmanuel Vadot 		if ((m->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) != 0) {
189972adf0fSEmmanuel Vadot 			if (sc->mactype != DWC_GMAC_EXT_DESC)
190972adf0fSEmmanuel Vadot 				flags = NTDESC1_CIC_FULL;
191972adf0fSEmmanuel Vadot 			else
192972adf0fSEmmanuel Vadot 				flags = ETDESC0_CIC_FULL;
193972adf0fSEmmanuel Vadot 		} else {
194972adf0fSEmmanuel Vadot 			if (sc->mactype != DWC_GMAC_EXT_DESC)
195972adf0fSEmmanuel Vadot 				flags = NTDESC1_CIC_HDR;
196972adf0fSEmmanuel Vadot 			else
197972adf0fSEmmanuel Vadot 				flags = ETDESC0_CIC_HDR;
198972adf0fSEmmanuel Vadot 		}
199972adf0fSEmmanuel Vadot 	}
200972adf0fSEmmanuel Vadot 
201972adf0fSEmmanuel Vadot 	bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map,
202972adf0fSEmmanuel Vadot 	    BUS_DMASYNC_PREWRITE);
203972adf0fSEmmanuel Vadot 
204972adf0fSEmmanuel Vadot 	sc->txbuf_map[idx].mbuf = m;
205972adf0fSEmmanuel Vadot 
206972adf0fSEmmanuel Vadot 	first = sc->tx_desc_head;
207972adf0fSEmmanuel Vadot 	for (i = 0; i < nsegs; i++) {
208972adf0fSEmmanuel Vadot 		dwc_setup_txdesc(sc, sc->tx_desc_head,
209972adf0fSEmmanuel Vadot 		    segs[i].ds_addr, segs[i].ds_len,
210972adf0fSEmmanuel Vadot 		    (i == 0) ? flags : 0, /* only first desc needs flags */
211972adf0fSEmmanuel Vadot 		    (i == 0),
212972adf0fSEmmanuel Vadot 		    (i == nsegs - 1));
213972adf0fSEmmanuel Vadot 		if (i > 0)
214972adf0fSEmmanuel Vadot 			dwc_set_owner(sc, sc->tx_desc_head);
215972adf0fSEmmanuel Vadot 		last = sc->tx_desc_head;
216972adf0fSEmmanuel Vadot 		sc->tx_desc_head = next_txidx(sc, sc->tx_desc_head);
217972adf0fSEmmanuel Vadot 	}
218972adf0fSEmmanuel Vadot 
219972adf0fSEmmanuel Vadot 	sc->txbuf_map[idx].last_desc_idx = last;
220972adf0fSEmmanuel Vadot 
221972adf0fSEmmanuel Vadot 	dwc_set_owner(sc, first);
222972adf0fSEmmanuel Vadot 
223972adf0fSEmmanuel Vadot 	return (0);
224972adf0fSEmmanuel Vadot }
225972adf0fSEmmanuel Vadot 
226972adf0fSEmmanuel Vadot static int
227972adf0fSEmmanuel Vadot dma1000_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m)
228972adf0fSEmmanuel Vadot {
229972adf0fSEmmanuel Vadot 	struct bus_dma_segment seg;
230972adf0fSEmmanuel Vadot 	int error, nsegs;
231972adf0fSEmmanuel Vadot 
232972adf0fSEmmanuel Vadot 	m_adj(m, ETHER_ALIGN);
233972adf0fSEmmanuel Vadot 
234972adf0fSEmmanuel Vadot 	error = bus_dmamap_load_mbuf_sg(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
235972adf0fSEmmanuel Vadot 	    m, &seg, &nsegs, 0);
236972adf0fSEmmanuel Vadot 	if (error != 0)
237972adf0fSEmmanuel Vadot 		return (error);
238972adf0fSEmmanuel Vadot 
239972adf0fSEmmanuel Vadot 	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
240972adf0fSEmmanuel Vadot 
241972adf0fSEmmanuel Vadot 	bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
242972adf0fSEmmanuel Vadot 	    BUS_DMASYNC_PREREAD);
243972adf0fSEmmanuel Vadot 
244972adf0fSEmmanuel Vadot 	sc->rxbuf_map[idx].mbuf = m;
245972adf0fSEmmanuel Vadot 	dwc_setup_rxdesc(sc, idx, seg.ds_addr);
246972adf0fSEmmanuel Vadot 
247972adf0fSEmmanuel Vadot 	return (0);
248972adf0fSEmmanuel Vadot }
249972adf0fSEmmanuel Vadot 
250972adf0fSEmmanuel Vadot static struct mbuf *
251972adf0fSEmmanuel Vadot dwc_alloc_mbufcl(struct dwc_softc *sc)
252972adf0fSEmmanuel Vadot {
253972adf0fSEmmanuel Vadot 	struct mbuf *m;
254972adf0fSEmmanuel Vadot 
255972adf0fSEmmanuel Vadot 	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
256972adf0fSEmmanuel Vadot 	if (m != NULL)
257972adf0fSEmmanuel Vadot 		m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
258972adf0fSEmmanuel Vadot 
259972adf0fSEmmanuel Vadot 	return (m);
260972adf0fSEmmanuel Vadot }
261972adf0fSEmmanuel Vadot 
262972adf0fSEmmanuel Vadot static struct mbuf *
263972adf0fSEmmanuel Vadot dwc_rxfinish_one(struct dwc_softc *sc, struct dwc_hwdesc *desc,
264972adf0fSEmmanuel Vadot     struct dwc_bufmap *map)
265972adf0fSEmmanuel Vadot {
266972adf0fSEmmanuel Vadot 	if_t ifp;
267972adf0fSEmmanuel Vadot 	struct mbuf *m, *m0;
268972adf0fSEmmanuel Vadot 	int len;
269972adf0fSEmmanuel Vadot 	uint32_t rdesc0;
270972adf0fSEmmanuel Vadot 
271972adf0fSEmmanuel Vadot 	m = map->mbuf;
272972adf0fSEmmanuel Vadot 	ifp = sc->ifp;
273972adf0fSEmmanuel Vadot 	rdesc0 = desc ->desc0;
274972adf0fSEmmanuel Vadot 
275972adf0fSEmmanuel Vadot 	if ((rdesc0 & (RDESC0_FS | RDESC0_LS)) !=
276972adf0fSEmmanuel Vadot 		    (RDESC0_FS | RDESC0_LS)) {
277972adf0fSEmmanuel Vadot 		/*
278972adf0fSEmmanuel Vadot 		 * Something very wrong happens. The whole packet should be
279972adf0fSEmmanuel Vadot 		 * recevied in one descriptr. Report problem.
280972adf0fSEmmanuel Vadot 		 */
281972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
282972adf0fSEmmanuel Vadot 		    "%s: RX descriptor without FIRST and LAST bit set: 0x%08X",
283972adf0fSEmmanuel Vadot 		    __func__, rdesc0);
284972adf0fSEmmanuel Vadot 		return (NULL);
285972adf0fSEmmanuel Vadot 	}
286972adf0fSEmmanuel Vadot 
287972adf0fSEmmanuel Vadot 	len = (rdesc0 >> RDESC0_FL_SHIFT) & RDESC0_FL_MASK;
288972adf0fSEmmanuel Vadot 	if (len < 64) {
289972adf0fSEmmanuel Vadot 		/*
290972adf0fSEmmanuel Vadot 		 * Lenght is invalid, recycle old mbuf
291972adf0fSEmmanuel Vadot 		 * Probably impossible case
292972adf0fSEmmanuel Vadot 		 */
293972adf0fSEmmanuel Vadot 		return (NULL);
294972adf0fSEmmanuel Vadot 	}
295972adf0fSEmmanuel Vadot 
296972adf0fSEmmanuel Vadot 	/* Allocate new buffer */
297972adf0fSEmmanuel Vadot 	m0 = dwc_alloc_mbufcl(sc);
298972adf0fSEmmanuel Vadot 	if (m0 == NULL) {
299972adf0fSEmmanuel Vadot 		/* no new mbuf available, recycle old */
300972adf0fSEmmanuel Vadot 		if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1);
301972adf0fSEmmanuel Vadot 		return (NULL);
302972adf0fSEmmanuel Vadot 	}
303972adf0fSEmmanuel Vadot 	/* Do dmasync for newly received packet */
304972adf0fSEmmanuel Vadot 	bus_dmamap_sync(sc->rxbuf_tag, map->map, BUS_DMASYNC_POSTREAD);
305972adf0fSEmmanuel Vadot 	bus_dmamap_unload(sc->rxbuf_tag, map->map);
306972adf0fSEmmanuel Vadot 
307972adf0fSEmmanuel Vadot 	/* Received packet is valid, process it */
308972adf0fSEmmanuel Vadot 	m->m_pkthdr.rcvif = ifp;
309972adf0fSEmmanuel Vadot 	m->m_pkthdr.len = len;
310972adf0fSEmmanuel Vadot 	m->m_len = len;
311972adf0fSEmmanuel Vadot 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
312972adf0fSEmmanuel Vadot 
313972adf0fSEmmanuel Vadot 	if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0 &&
314972adf0fSEmmanuel Vadot 	  (rdesc0 & RDESC0_FT) != 0) {
315972adf0fSEmmanuel Vadot 		m->m_pkthdr.csum_flags = CSUM_IP_CHECKED;
316972adf0fSEmmanuel Vadot 		if ((rdesc0 & RDESC0_ICE) == 0)
317972adf0fSEmmanuel Vadot 			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
318972adf0fSEmmanuel Vadot 		if ((rdesc0 & RDESC0_PCE) == 0) {
319972adf0fSEmmanuel Vadot 			m->m_pkthdr.csum_flags |=
320972adf0fSEmmanuel Vadot 				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
321972adf0fSEmmanuel Vadot 			m->m_pkthdr.csum_data = 0xffff;
322972adf0fSEmmanuel Vadot 		}
323972adf0fSEmmanuel Vadot 	}
324972adf0fSEmmanuel Vadot 
325972adf0fSEmmanuel Vadot 	/* Remove trailing FCS */
326972adf0fSEmmanuel Vadot 	m_adj(m, -ETHER_CRC_LEN);
327972adf0fSEmmanuel Vadot 
328972adf0fSEmmanuel Vadot 	DWC_UNLOCK(sc);
329972adf0fSEmmanuel Vadot 	if_input(ifp, m);
330972adf0fSEmmanuel Vadot 	DWC_LOCK(sc);
331972adf0fSEmmanuel Vadot 	return (m0);
332972adf0fSEmmanuel Vadot }
333972adf0fSEmmanuel Vadot 
334972adf0fSEmmanuel Vadot void
335972adf0fSEmmanuel Vadot dma1000_txfinish_locked(struct dwc_softc *sc)
336972adf0fSEmmanuel Vadot {
337972adf0fSEmmanuel Vadot 	struct dwc_bufmap *bmap;
338972adf0fSEmmanuel Vadot 	struct dwc_hwdesc *desc;
339972adf0fSEmmanuel Vadot 	if_t ifp;
340972adf0fSEmmanuel Vadot 	int idx, last_idx;
341972adf0fSEmmanuel Vadot 	bool map_finished;
342972adf0fSEmmanuel Vadot 
343972adf0fSEmmanuel Vadot 	DWC_ASSERT_LOCKED(sc);
344972adf0fSEmmanuel Vadot 
345972adf0fSEmmanuel Vadot 	ifp = sc->ifp;
346972adf0fSEmmanuel Vadot 	/* check if all descriptors of the map are done */
347972adf0fSEmmanuel Vadot 	while (sc->tx_map_tail != sc->tx_map_head) {
348972adf0fSEmmanuel Vadot 		map_finished = true;
349972adf0fSEmmanuel Vadot 		bmap = &sc->txbuf_map[sc->tx_map_tail];
350972adf0fSEmmanuel Vadot 		idx = sc->tx_desc_tail;
351972adf0fSEmmanuel Vadot 		last_idx = next_txidx(sc, bmap->last_desc_idx);
352972adf0fSEmmanuel Vadot 		while (idx != last_idx) {
353972adf0fSEmmanuel Vadot 			desc = &sc->txdesc_ring[idx];
354972adf0fSEmmanuel Vadot 			if ((desc->desc0 & TDESC0_OWN) != 0) {
355972adf0fSEmmanuel Vadot 				map_finished = false;
356972adf0fSEmmanuel Vadot 				break;
357972adf0fSEmmanuel Vadot 			}
358972adf0fSEmmanuel Vadot 			idx = next_txidx(sc, idx);
359972adf0fSEmmanuel Vadot 		}
360972adf0fSEmmanuel Vadot 
361972adf0fSEmmanuel Vadot 		if (!map_finished)
362972adf0fSEmmanuel Vadot 			break;
363972adf0fSEmmanuel Vadot 		bus_dmamap_sync(sc->txbuf_tag, bmap->map,
364972adf0fSEmmanuel Vadot 		    BUS_DMASYNC_POSTWRITE);
365972adf0fSEmmanuel Vadot 		bus_dmamap_unload(sc->txbuf_tag, bmap->map);
366972adf0fSEmmanuel Vadot 		m_freem(bmap->mbuf);
367972adf0fSEmmanuel Vadot 		bmap->mbuf = NULL;
368972adf0fSEmmanuel Vadot 		sc->tx_mapcount--;
369972adf0fSEmmanuel Vadot 		while (sc->tx_desc_tail != last_idx) {
370972adf0fSEmmanuel Vadot 			dwc_setup_txdesc(sc, sc->tx_desc_tail, 0, 0, 0, false, false);
371972adf0fSEmmanuel Vadot 			sc->tx_desc_tail = next_txidx(sc, sc->tx_desc_tail);
372972adf0fSEmmanuel Vadot 		}
373972adf0fSEmmanuel Vadot 		sc->tx_map_tail = next_txidx(sc, sc->tx_map_tail);
374972adf0fSEmmanuel Vadot 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
375972adf0fSEmmanuel Vadot 		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
376972adf0fSEmmanuel Vadot 	}
377972adf0fSEmmanuel Vadot 
378972adf0fSEmmanuel Vadot 	/* If there are no buffers outstanding, muzzle the watchdog. */
379972adf0fSEmmanuel Vadot 	if (sc->tx_desc_tail == sc->tx_desc_head) {
380972adf0fSEmmanuel Vadot 		sc->tx_watchdog_count = 0;
381972adf0fSEmmanuel Vadot 	}
382972adf0fSEmmanuel Vadot }
383972adf0fSEmmanuel Vadot 
384972adf0fSEmmanuel Vadot void
385*afa0f66eSEmmanuel Vadot dma1000_txstart(struct dwc_softc *sc)
386*afa0f66eSEmmanuel Vadot {
387*afa0f66eSEmmanuel Vadot 	int enqueued;
388*afa0f66eSEmmanuel Vadot 	struct mbuf *m;
389*afa0f66eSEmmanuel Vadot 
390*afa0f66eSEmmanuel Vadot 	enqueued = 0;
391*afa0f66eSEmmanuel Vadot 
392*afa0f66eSEmmanuel Vadot 	for (;;) {
393*afa0f66eSEmmanuel Vadot 		if (sc->tx_desccount > (TX_DESC_COUNT - TX_MAP_MAX_SEGS  + 1)) {
394*afa0f66eSEmmanuel Vadot 			if_setdrvflagbits(sc->ifp, IFF_DRV_OACTIVE, 0);
395*afa0f66eSEmmanuel Vadot 			break;
396*afa0f66eSEmmanuel Vadot 		}
397*afa0f66eSEmmanuel Vadot 
398*afa0f66eSEmmanuel Vadot 		if (sc->tx_mapcount == (TX_MAP_COUNT - 1)) {
399*afa0f66eSEmmanuel Vadot 			if_setdrvflagbits(sc->ifp, IFF_DRV_OACTIVE, 0);
400*afa0f66eSEmmanuel Vadot 			break;
401*afa0f66eSEmmanuel Vadot 		}
402*afa0f66eSEmmanuel Vadot 
403*afa0f66eSEmmanuel Vadot 		m = if_dequeue(sc->ifp);
404*afa0f66eSEmmanuel Vadot 		if (m == NULL)
405*afa0f66eSEmmanuel Vadot 			break;
406*afa0f66eSEmmanuel Vadot 		if (dma1000_setup_txbuf(sc, sc->tx_map_head, &m) != 0) {
407*afa0f66eSEmmanuel Vadot 			if_sendq_prepend(sc->ifp, m);
408*afa0f66eSEmmanuel Vadot 			if_setdrvflagbits(sc->ifp, IFF_DRV_OACTIVE, 0);
409*afa0f66eSEmmanuel Vadot 			break;
410*afa0f66eSEmmanuel Vadot 		}
411*afa0f66eSEmmanuel Vadot 		bpf_mtap_if(sc->ifp, m);
412*afa0f66eSEmmanuel Vadot 		sc->tx_map_head = next_txidx(sc, sc->tx_map_head);
413*afa0f66eSEmmanuel Vadot 		sc->tx_mapcount++;
414*afa0f66eSEmmanuel Vadot 		++enqueued;
415*afa0f66eSEmmanuel Vadot 	}
416*afa0f66eSEmmanuel Vadot 
417*afa0f66eSEmmanuel Vadot 	if (enqueued != 0) {
418*afa0f66eSEmmanuel Vadot 		WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1);
419*afa0f66eSEmmanuel Vadot 		sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS;
420*afa0f66eSEmmanuel Vadot 	}
421*afa0f66eSEmmanuel Vadot }
422*afa0f66eSEmmanuel Vadot 
423*afa0f66eSEmmanuel Vadot void
424972adf0fSEmmanuel Vadot dma1000_rxfinish_locked(struct dwc_softc *sc)
425972adf0fSEmmanuel Vadot {
426972adf0fSEmmanuel Vadot 	struct mbuf *m;
427972adf0fSEmmanuel Vadot 	int error, idx;
428972adf0fSEmmanuel Vadot 	struct dwc_hwdesc *desc;
429972adf0fSEmmanuel Vadot 
430972adf0fSEmmanuel Vadot 	DWC_ASSERT_LOCKED(sc);
431972adf0fSEmmanuel Vadot 	for (;;) {
432972adf0fSEmmanuel Vadot 		idx = sc->rx_idx;
433972adf0fSEmmanuel Vadot 		desc = sc->rxdesc_ring + idx;
434972adf0fSEmmanuel Vadot 		if ((desc->desc0 & RDESC0_OWN) != 0)
435972adf0fSEmmanuel Vadot 			break;
436972adf0fSEmmanuel Vadot 
437972adf0fSEmmanuel Vadot 		m = dwc_rxfinish_one(sc, desc, sc->rxbuf_map + idx);
438972adf0fSEmmanuel Vadot 		if (m == NULL) {
439972adf0fSEmmanuel Vadot 			wmb();
440972adf0fSEmmanuel Vadot 			desc->desc0 = RDESC0_OWN;
441972adf0fSEmmanuel Vadot 			wmb();
442972adf0fSEmmanuel Vadot 		} else {
443972adf0fSEmmanuel Vadot 			/* We cannot create hole in RX ring */
444972adf0fSEmmanuel Vadot 			error = dma1000_setup_rxbuf(sc, idx, m);
445972adf0fSEmmanuel Vadot 			if (error != 0)
446972adf0fSEmmanuel Vadot 				panic("dma1000_setup_rxbuf failed:  error %d\n",
447972adf0fSEmmanuel Vadot 				    error);
448972adf0fSEmmanuel Vadot 
449972adf0fSEmmanuel Vadot 		}
450972adf0fSEmmanuel Vadot 		sc->rx_idx = next_rxidx(sc, sc->rx_idx);
451972adf0fSEmmanuel Vadot 	}
452972adf0fSEmmanuel Vadot }
453972adf0fSEmmanuel Vadot 
454972adf0fSEmmanuel Vadot /*
455972adf0fSEmmanuel Vadot  * Start the DMA controller
456972adf0fSEmmanuel Vadot  */
457972adf0fSEmmanuel Vadot void
458972adf0fSEmmanuel Vadot dma1000_start(struct dwc_softc *sc)
459972adf0fSEmmanuel Vadot {
460972adf0fSEmmanuel Vadot 	uint32_t reg;
461972adf0fSEmmanuel Vadot 
462972adf0fSEmmanuel Vadot 	DWC_ASSERT_LOCKED(sc);
463972adf0fSEmmanuel Vadot 
464972adf0fSEmmanuel Vadot 	/* Initializa DMA and enable transmitters */
465972adf0fSEmmanuel Vadot 	reg = READ4(sc, OPERATION_MODE);
466972adf0fSEmmanuel Vadot 	reg |= (MODE_TSF | MODE_OSF | MODE_FUF);
467972adf0fSEmmanuel Vadot 	reg &= ~(MODE_RSF);
468972adf0fSEmmanuel Vadot 	reg |= (MODE_RTC_LEV32 << MODE_RTC_SHIFT);
469972adf0fSEmmanuel Vadot 	WRITE4(sc, OPERATION_MODE, reg);
470972adf0fSEmmanuel Vadot 
471972adf0fSEmmanuel Vadot 	WRITE4(sc, INTERRUPT_ENABLE, INT_EN_DEFAULT);
472972adf0fSEmmanuel Vadot 
473972adf0fSEmmanuel Vadot 	/* Start DMA */
474972adf0fSEmmanuel Vadot 	reg = READ4(sc, OPERATION_MODE);
475972adf0fSEmmanuel Vadot 	reg |= (MODE_ST | MODE_SR);
476972adf0fSEmmanuel Vadot 	WRITE4(sc, OPERATION_MODE, reg);
477972adf0fSEmmanuel Vadot }
478972adf0fSEmmanuel Vadot 
479972adf0fSEmmanuel Vadot /*
480972adf0fSEmmanuel Vadot  * Stop the DMA controller
481972adf0fSEmmanuel Vadot  */
482972adf0fSEmmanuel Vadot void
483972adf0fSEmmanuel Vadot dma1000_stop(struct dwc_softc *sc)
484972adf0fSEmmanuel Vadot {
485972adf0fSEmmanuel Vadot 	uint32_t reg;
486972adf0fSEmmanuel Vadot 
487972adf0fSEmmanuel Vadot 	DWC_ASSERT_LOCKED(sc);
488972adf0fSEmmanuel Vadot 
489972adf0fSEmmanuel Vadot 	/* Stop DMA TX */
490972adf0fSEmmanuel Vadot 	reg = READ4(sc, OPERATION_MODE);
491972adf0fSEmmanuel Vadot 	reg &= ~(MODE_ST);
492972adf0fSEmmanuel Vadot 	WRITE4(sc, OPERATION_MODE, reg);
493972adf0fSEmmanuel Vadot 
494972adf0fSEmmanuel Vadot 	/* Flush TX */
495972adf0fSEmmanuel Vadot 	reg = READ4(sc, OPERATION_MODE);
496972adf0fSEmmanuel Vadot 	reg |= (MODE_FTF);
497972adf0fSEmmanuel Vadot 	WRITE4(sc, OPERATION_MODE, reg);
498972adf0fSEmmanuel Vadot 
499972adf0fSEmmanuel Vadot 	/* Stop DMA RX */
500972adf0fSEmmanuel Vadot 	reg = READ4(sc, OPERATION_MODE);
501972adf0fSEmmanuel Vadot 	reg &= ~(MODE_SR);
502972adf0fSEmmanuel Vadot 	WRITE4(sc, OPERATION_MODE, reg);
503972adf0fSEmmanuel Vadot }
504972adf0fSEmmanuel Vadot 
505972adf0fSEmmanuel Vadot /*
506972adf0fSEmmanuel Vadot  * Create the bus_dma resources
507972adf0fSEmmanuel Vadot  */
508972adf0fSEmmanuel Vadot int
509972adf0fSEmmanuel Vadot dma1000_init(struct dwc_softc *sc)
510972adf0fSEmmanuel Vadot {
511972adf0fSEmmanuel Vadot 	struct mbuf *m;
512972adf0fSEmmanuel Vadot 	int error;
513972adf0fSEmmanuel Vadot 	int nidx;
514972adf0fSEmmanuel Vadot 	int idx;
515972adf0fSEmmanuel Vadot 
516972adf0fSEmmanuel Vadot 	/*
517972adf0fSEmmanuel Vadot 	 * Set up TX descriptor ring, descriptors, and dma maps.
518972adf0fSEmmanuel Vadot 	 */
519972adf0fSEmmanuel Vadot 	error = bus_dma_tag_create(
520972adf0fSEmmanuel Vadot 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
521972adf0fSEmmanuel Vadot 	    DWC_DESC_RING_ALIGN, 0,	/* alignment, boundary */
522972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
523972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR,		/* highaddr */
524972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* filter, filterarg */
525972adf0fSEmmanuel Vadot 	    TX_DESC_SIZE, 1, 		/* maxsize, nsegments */
526972adf0fSEmmanuel Vadot 	    TX_DESC_SIZE,		/* maxsegsize */
527972adf0fSEmmanuel Vadot 	    0,				/* flags */
528972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* lockfunc, lockarg */
529972adf0fSEmmanuel Vadot 	    &sc->txdesc_tag);
530972adf0fSEmmanuel Vadot 	if (error != 0) {
531972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
532972adf0fSEmmanuel Vadot 		    "could not create TX ring DMA tag.\n");
533972adf0fSEmmanuel Vadot 		goto out;
534972adf0fSEmmanuel Vadot 	}
535972adf0fSEmmanuel Vadot 
536972adf0fSEmmanuel Vadot 	error = bus_dmamem_alloc(sc->txdesc_tag, (void**)&sc->txdesc_ring,
537972adf0fSEmmanuel Vadot 	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
538972adf0fSEmmanuel Vadot 	    &sc->txdesc_map);
539972adf0fSEmmanuel Vadot 	if (error != 0) {
540972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
541972adf0fSEmmanuel Vadot 		    "could not allocate TX descriptor ring.\n");
542972adf0fSEmmanuel Vadot 		goto out;
543972adf0fSEmmanuel Vadot 	}
544972adf0fSEmmanuel Vadot 
545972adf0fSEmmanuel Vadot 	error = bus_dmamap_load(sc->txdesc_tag, sc->txdesc_map,
546972adf0fSEmmanuel Vadot 	    sc->txdesc_ring, TX_DESC_SIZE, dwc_get1paddr,
547972adf0fSEmmanuel Vadot 	    &sc->txdesc_ring_paddr, 0);
548972adf0fSEmmanuel Vadot 	if (error != 0) {
549972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
550972adf0fSEmmanuel Vadot 		    "could not load TX descriptor ring map.\n");
551972adf0fSEmmanuel Vadot 		goto out;
552972adf0fSEmmanuel Vadot 	}
553972adf0fSEmmanuel Vadot 
554972adf0fSEmmanuel Vadot 	for (idx = 0; idx < TX_DESC_COUNT; idx++) {
555972adf0fSEmmanuel Vadot 		nidx = next_txidx(sc, idx);
556972adf0fSEmmanuel Vadot 		sc->txdesc_ring[idx].addr2 = sc->txdesc_ring_paddr +
557972adf0fSEmmanuel Vadot 		    (nidx * sizeof(struct dwc_hwdesc));
558972adf0fSEmmanuel Vadot 	}
559972adf0fSEmmanuel Vadot 
560972adf0fSEmmanuel Vadot 	error = bus_dma_tag_create(
561972adf0fSEmmanuel Vadot 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
562972adf0fSEmmanuel Vadot 	    1, 0,			/* alignment, boundary */
563972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
564972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR,		/* highaddr */
565972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* filter, filterarg */
566972adf0fSEmmanuel Vadot 	    MCLBYTES*TX_MAP_MAX_SEGS,	/* maxsize */
567972adf0fSEmmanuel Vadot 	    TX_MAP_MAX_SEGS,		/* nsegments */
568972adf0fSEmmanuel Vadot 	    MCLBYTES,			/* maxsegsize */
569972adf0fSEmmanuel Vadot 	    0,				/* flags */
570972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* lockfunc, lockarg */
571972adf0fSEmmanuel Vadot 	    &sc->txbuf_tag);
572972adf0fSEmmanuel Vadot 	if (error != 0) {
573972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
574972adf0fSEmmanuel Vadot 		    "could not create TX ring DMA tag.\n");
575972adf0fSEmmanuel Vadot 		goto out;
576972adf0fSEmmanuel Vadot 	}
577972adf0fSEmmanuel Vadot 
578972adf0fSEmmanuel Vadot 	for (idx = 0; idx < TX_MAP_COUNT; idx++) {
579972adf0fSEmmanuel Vadot 		error = bus_dmamap_create(sc->txbuf_tag, BUS_DMA_COHERENT,
580972adf0fSEmmanuel Vadot 		    &sc->txbuf_map[idx].map);
581972adf0fSEmmanuel Vadot 		if (error != 0) {
582972adf0fSEmmanuel Vadot 			device_printf(sc->dev,
583972adf0fSEmmanuel Vadot 			    "could not create TX buffer DMA map.\n");
584972adf0fSEmmanuel Vadot 			goto out;
585972adf0fSEmmanuel Vadot 		}
586972adf0fSEmmanuel Vadot 	}
587972adf0fSEmmanuel Vadot 
588972adf0fSEmmanuel Vadot 	for (idx = 0; idx < TX_DESC_COUNT; idx++)
589972adf0fSEmmanuel Vadot 		dwc_setup_txdesc(sc, idx, 0, 0, 0, false, false);
590972adf0fSEmmanuel Vadot 
591972adf0fSEmmanuel Vadot 	/*
592972adf0fSEmmanuel Vadot 	 * Set up RX descriptor ring, descriptors, dma maps, and mbufs.
593972adf0fSEmmanuel Vadot 	 */
594972adf0fSEmmanuel Vadot 	error = bus_dma_tag_create(
595972adf0fSEmmanuel Vadot 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
596972adf0fSEmmanuel Vadot 	    DWC_DESC_RING_ALIGN, 0,	/* alignment, boundary */
597972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
598972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR,		/* highaddr */
599972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* filter, filterarg */
600972adf0fSEmmanuel Vadot 	    RX_DESC_SIZE, 1, 		/* maxsize, nsegments */
601972adf0fSEmmanuel Vadot 	    RX_DESC_SIZE,		/* maxsegsize */
602972adf0fSEmmanuel Vadot 	    0,				/* flags */
603972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* lockfunc, lockarg */
604972adf0fSEmmanuel Vadot 	    &sc->rxdesc_tag);
605972adf0fSEmmanuel Vadot 	if (error != 0) {
606972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
607972adf0fSEmmanuel Vadot 		    "could not create RX ring DMA tag.\n");
608972adf0fSEmmanuel Vadot 		goto out;
609972adf0fSEmmanuel Vadot 	}
610972adf0fSEmmanuel Vadot 
611972adf0fSEmmanuel Vadot 	error = bus_dmamem_alloc(sc->rxdesc_tag, (void **)&sc->rxdesc_ring,
612972adf0fSEmmanuel Vadot 	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
613972adf0fSEmmanuel Vadot 	    &sc->rxdesc_map);
614972adf0fSEmmanuel Vadot 	if (error != 0) {
615972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
616972adf0fSEmmanuel Vadot 		    "could not allocate RX descriptor ring.\n");
617972adf0fSEmmanuel Vadot 		goto out;
618972adf0fSEmmanuel Vadot 	}
619972adf0fSEmmanuel Vadot 
620972adf0fSEmmanuel Vadot 	error = bus_dmamap_load(sc->rxdesc_tag, sc->rxdesc_map,
621972adf0fSEmmanuel Vadot 	    sc->rxdesc_ring, RX_DESC_SIZE, dwc_get1paddr,
622972adf0fSEmmanuel Vadot 	    &sc->rxdesc_ring_paddr, 0);
623972adf0fSEmmanuel Vadot 	if (error != 0) {
624972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
625972adf0fSEmmanuel Vadot 		    "could not load RX descriptor ring map.\n");
626972adf0fSEmmanuel Vadot 		goto out;
627972adf0fSEmmanuel Vadot 	}
628972adf0fSEmmanuel Vadot 
629972adf0fSEmmanuel Vadot 	error = bus_dma_tag_create(
630972adf0fSEmmanuel Vadot 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
631972adf0fSEmmanuel Vadot 	    1, 0,			/* alignment, boundary */
632972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
633972adf0fSEmmanuel Vadot 	    BUS_SPACE_MAXADDR,		/* highaddr */
634972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* filter, filterarg */
635972adf0fSEmmanuel Vadot 	    MCLBYTES, 1, 		/* maxsize, nsegments */
636972adf0fSEmmanuel Vadot 	    MCLBYTES,			/* maxsegsize */
637972adf0fSEmmanuel Vadot 	    0,				/* flags */
638972adf0fSEmmanuel Vadot 	    NULL, NULL,			/* lockfunc, lockarg */
639972adf0fSEmmanuel Vadot 	    &sc->rxbuf_tag);
640972adf0fSEmmanuel Vadot 	if (error != 0) {
641972adf0fSEmmanuel Vadot 		device_printf(sc->dev,
642972adf0fSEmmanuel Vadot 		    "could not create RX buf DMA tag.\n");
643972adf0fSEmmanuel Vadot 		goto out;
644972adf0fSEmmanuel Vadot 	}
645972adf0fSEmmanuel Vadot 
646972adf0fSEmmanuel Vadot 	for (idx = 0; idx < RX_DESC_COUNT; idx++) {
647972adf0fSEmmanuel Vadot 		error = bus_dmamap_create(sc->rxbuf_tag, BUS_DMA_COHERENT,
648972adf0fSEmmanuel Vadot 		    &sc->rxbuf_map[idx].map);
649972adf0fSEmmanuel Vadot 		if (error != 0) {
650972adf0fSEmmanuel Vadot 			device_printf(sc->dev,
651972adf0fSEmmanuel Vadot 			    "could not create RX buffer DMA map.\n");
652972adf0fSEmmanuel Vadot 			goto out;
653972adf0fSEmmanuel Vadot 		}
654972adf0fSEmmanuel Vadot 		if ((m = dwc_alloc_mbufcl(sc)) == NULL) {
655972adf0fSEmmanuel Vadot 			device_printf(sc->dev, "Could not alloc mbuf\n");
656972adf0fSEmmanuel Vadot 			error = ENOMEM;
657972adf0fSEmmanuel Vadot 			goto out;
658972adf0fSEmmanuel Vadot 		}
659972adf0fSEmmanuel Vadot 		if ((error = dma1000_setup_rxbuf(sc, idx, m)) != 0) {
660972adf0fSEmmanuel Vadot 			device_printf(sc->dev,
661972adf0fSEmmanuel Vadot 			    "could not create new RX buffer.\n");
662972adf0fSEmmanuel Vadot 			goto out;
663972adf0fSEmmanuel Vadot 		}
664972adf0fSEmmanuel Vadot 	}
665972adf0fSEmmanuel Vadot 
666972adf0fSEmmanuel Vadot out:
667972adf0fSEmmanuel Vadot 	if (error != 0)
668972adf0fSEmmanuel Vadot 		return (ENXIO);
669972adf0fSEmmanuel Vadot 
670972adf0fSEmmanuel Vadot 	return (0);
671972adf0fSEmmanuel Vadot }
672972adf0fSEmmanuel Vadot 
673972adf0fSEmmanuel Vadot /*
674972adf0fSEmmanuel Vadot  * Free the bus_dma resources
675972adf0fSEmmanuel Vadot  */
676972adf0fSEmmanuel Vadot void
677972adf0fSEmmanuel Vadot dma1000_free(struct dwc_softc *sc)
678972adf0fSEmmanuel Vadot {
679972adf0fSEmmanuel Vadot 	bus_dmamap_t map;
680972adf0fSEmmanuel Vadot 	int idx;
681972adf0fSEmmanuel Vadot 
682972adf0fSEmmanuel Vadot 	/* Clean up RX DMA resources and free mbufs. */
683972adf0fSEmmanuel Vadot 	for (idx = 0; idx < RX_DESC_COUNT; ++idx) {
684972adf0fSEmmanuel Vadot 		if ((map = sc->rxbuf_map[idx].map) != NULL) {
685972adf0fSEmmanuel Vadot 			bus_dmamap_unload(sc->rxbuf_tag, map);
686972adf0fSEmmanuel Vadot 			bus_dmamap_destroy(sc->rxbuf_tag, map);
687972adf0fSEmmanuel Vadot 			m_freem(sc->rxbuf_map[idx].mbuf);
688972adf0fSEmmanuel Vadot 		}
689972adf0fSEmmanuel Vadot 	}
690972adf0fSEmmanuel Vadot 	if (sc->rxbuf_tag != NULL)
691972adf0fSEmmanuel Vadot 		bus_dma_tag_destroy(sc->rxbuf_tag);
692972adf0fSEmmanuel Vadot 	if (sc->rxdesc_map != NULL) {
693972adf0fSEmmanuel Vadot 		bus_dmamap_unload(sc->rxdesc_tag, sc->rxdesc_map);
694972adf0fSEmmanuel Vadot 		bus_dmamem_free(sc->rxdesc_tag, sc->rxdesc_ring,
695972adf0fSEmmanuel Vadot 		    sc->rxdesc_map);
696972adf0fSEmmanuel Vadot 	}
697972adf0fSEmmanuel Vadot 	if (sc->rxdesc_tag != NULL)
698972adf0fSEmmanuel Vadot 		bus_dma_tag_destroy(sc->rxdesc_tag);
699972adf0fSEmmanuel Vadot 
700972adf0fSEmmanuel Vadot 	/* Clean up TX DMA resources. */
701972adf0fSEmmanuel Vadot 	for (idx = 0; idx < TX_DESC_COUNT; ++idx) {
702972adf0fSEmmanuel Vadot 		if ((map = sc->txbuf_map[idx].map) != NULL) {
703972adf0fSEmmanuel Vadot 			/* TX maps are already unloaded. */
704972adf0fSEmmanuel Vadot 			bus_dmamap_destroy(sc->txbuf_tag, map);
705972adf0fSEmmanuel Vadot 		}
706972adf0fSEmmanuel Vadot 	}
707972adf0fSEmmanuel Vadot 	if (sc->txbuf_tag != NULL)
708972adf0fSEmmanuel Vadot 		bus_dma_tag_destroy(sc->txbuf_tag);
709972adf0fSEmmanuel Vadot 	if (sc->txdesc_map != NULL) {
710972adf0fSEmmanuel Vadot 		bus_dmamap_unload(sc->txdesc_tag, sc->txdesc_map);
711972adf0fSEmmanuel Vadot 		bus_dmamem_free(sc->txdesc_tag, sc->txdesc_ring,
712972adf0fSEmmanuel Vadot 		    sc->txdesc_map);
713972adf0fSEmmanuel Vadot 	}
714972adf0fSEmmanuel Vadot 	if (sc->txdesc_tag != NULL)
715972adf0fSEmmanuel Vadot 		bus_dma_tag_destroy(sc->txdesc_tag);
716972adf0fSEmmanuel Vadot }
717