xref: /freebsd/sys/dev/xdma/xdma_fdt_test.c (revision 85debf7f6e3ef3bfc55df76c8525d7d4b08c5d77)
1*85debf7fSRuslan Bukin /*-
2*85debf7fSRuslan Bukin  * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
3*85debf7fSRuslan Bukin  * All rights reserved.
4*85debf7fSRuslan Bukin  *
5*85debf7fSRuslan Bukin  * This software was developed by SRI International and the University of
6*85debf7fSRuslan Bukin  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7*85debf7fSRuslan Bukin  * ("CTSRD"), as part of the DARPA CRASH research programme.
8*85debf7fSRuslan Bukin  *
9*85debf7fSRuslan Bukin  * Redistribution and use in source and binary forms, with or without
10*85debf7fSRuslan Bukin  * modification, are permitted provided that the following conditions
11*85debf7fSRuslan Bukin  * are met:
12*85debf7fSRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
13*85debf7fSRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
14*85debf7fSRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
15*85debf7fSRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
16*85debf7fSRuslan Bukin  *    documentation and/or other materials provided with the distribution.
17*85debf7fSRuslan Bukin  *
18*85debf7fSRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*85debf7fSRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*85debf7fSRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*85debf7fSRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*85debf7fSRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*85debf7fSRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*85debf7fSRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*85debf7fSRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*85debf7fSRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*85debf7fSRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*85debf7fSRuslan Bukin  * SUCH DAMAGE.
29*85debf7fSRuslan Bukin  */
30*85debf7fSRuslan Bukin 
31*85debf7fSRuslan Bukin /* xDMA memcpy test driver. */
32*85debf7fSRuslan Bukin 
33*85debf7fSRuslan Bukin #include <sys/cdefs.h>
34*85debf7fSRuslan Bukin __FBSDID("$FreeBSD$");
35*85debf7fSRuslan Bukin 
36*85debf7fSRuslan Bukin #include <sys/param.h>
37*85debf7fSRuslan Bukin #include <sys/systm.h>
38*85debf7fSRuslan Bukin #include <sys/conf.h>
39*85debf7fSRuslan Bukin #include <sys/bus.h>
40*85debf7fSRuslan Bukin #include <sys/kernel.h>
41*85debf7fSRuslan Bukin #include <sys/kthread.h>
42*85debf7fSRuslan Bukin #include <sys/module.h>
43*85debf7fSRuslan Bukin #include <sys/lock.h>
44*85debf7fSRuslan Bukin #include <sys/mutex.h>
45*85debf7fSRuslan Bukin #include <sys/resource.h>
46*85debf7fSRuslan Bukin #include <sys/rman.h>
47*85debf7fSRuslan Bukin 
48*85debf7fSRuslan Bukin #include <machine/bus.h>
49*85debf7fSRuslan Bukin 
50*85debf7fSRuslan Bukin #include <dev/xdma/xdma.h>
51*85debf7fSRuslan Bukin 
52*85debf7fSRuslan Bukin #include <dev/fdt/fdt_common.h>
53*85debf7fSRuslan Bukin #include <dev/ofw/ofw_bus.h>
54*85debf7fSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
55*85debf7fSRuslan Bukin 
56*85debf7fSRuslan Bukin /*
57*85debf7fSRuslan Bukin  * To use this test add a compatible node to your dts, e.g.
58*85debf7fSRuslan Bukin  *
59*85debf7fSRuslan Bukin  * 	xdma_test {
60*85debf7fSRuslan Bukin  *		compatible = "freebsd,xdma-test";
61*85debf7fSRuslan Bukin  *
62*85debf7fSRuslan Bukin  * 		dmas = <&dma 0 0 0xffffffff>;
63*85debf7fSRuslan Bukin  * 		dma-names = "test";
64*85debf7fSRuslan Bukin  *	};
65*85debf7fSRuslan Bukin  */
66*85debf7fSRuslan Bukin 
67*85debf7fSRuslan Bukin struct xdmatest_softc {
68*85debf7fSRuslan Bukin 	device_t		dev;
69*85debf7fSRuslan Bukin 	xdma_controller_t	*xdma;
70*85debf7fSRuslan Bukin 	xdma_channel_t		*xchan;
71*85debf7fSRuslan Bukin 	void			*ih;
72*85debf7fSRuslan Bukin 	struct intr_config_hook config_intrhook;
73*85debf7fSRuslan Bukin 	char			*src;
74*85debf7fSRuslan Bukin 	char			*dst;
75*85debf7fSRuslan Bukin 	uint32_t		len;
76*85debf7fSRuslan Bukin 	uintptr_t		src_phys;
77*85debf7fSRuslan Bukin 	uintptr_t		dst_phys;
78*85debf7fSRuslan Bukin 	bus_dma_tag_t		src_dma_tag;
79*85debf7fSRuslan Bukin 	bus_dmamap_t		src_dma_map;
80*85debf7fSRuslan Bukin 	bus_dma_tag_t		dst_dma_tag;
81*85debf7fSRuslan Bukin 	bus_dmamap_t		dst_dma_map;
82*85debf7fSRuslan Bukin 	struct mtx		mtx;
83*85debf7fSRuslan Bukin 	int			done;
84*85debf7fSRuslan Bukin 	struct proc		*newp;
85*85debf7fSRuslan Bukin };
86*85debf7fSRuslan Bukin 
87*85debf7fSRuslan Bukin static int xdmatest_probe(device_t dev);
88*85debf7fSRuslan Bukin static int xdmatest_attach(device_t dev);
89*85debf7fSRuslan Bukin static int xdmatest_detach(device_t dev);
90*85debf7fSRuslan Bukin 
91*85debf7fSRuslan Bukin static int
92*85debf7fSRuslan Bukin xdmatest_intr(void *arg)
93*85debf7fSRuslan Bukin {
94*85debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
95*85debf7fSRuslan Bukin 
96*85debf7fSRuslan Bukin 	sc = arg;
97*85debf7fSRuslan Bukin 
98*85debf7fSRuslan Bukin 	sc->done = 1;
99*85debf7fSRuslan Bukin 
100*85debf7fSRuslan Bukin 	mtx_lock(&sc->mtx);
101*85debf7fSRuslan Bukin 	wakeup(sc);
102*85debf7fSRuslan Bukin 	mtx_unlock(&sc->mtx);
103*85debf7fSRuslan Bukin 
104*85debf7fSRuslan Bukin 	return (0);
105*85debf7fSRuslan Bukin }
106*85debf7fSRuslan Bukin 
107*85debf7fSRuslan Bukin static void
108*85debf7fSRuslan Bukin xdmatest_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
109*85debf7fSRuslan Bukin {
110*85debf7fSRuslan Bukin 	bus_addr_t *addr;
111*85debf7fSRuslan Bukin 
112*85debf7fSRuslan Bukin 	if (err)
113*85debf7fSRuslan Bukin 		return;
114*85debf7fSRuslan Bukin 
115*85debf7fSRuslan Bukin 	addr = (bus_addr_t*)arg;
116*85debf7fSRuslan Bukin 	*addr = segs[0].ds_addr;
117*85debf7fSRuslan Bukin }
118*85debf7fSRuslan Bukin 
119*85debf7fSRuslan Bukin static int
120*85debf7fSRuslan Bukin xdmatest_alloc_test_memory(struct xdmatest_softc *sc)
121*85debf7fSRuslan Bukin {
122*85debf7fSRuslan Bukin 	int err;
123*85debf7fSRuslan Bukin 
124*85debf7fSRuslan Bukin 	sc->len = (0x1000000 - 8); /* 16mb */
125*85debf7fSRuslan Bukin 	sc->len = 8;
126*85debf7fSRuslan Bukin 
127*85debf7fSRuslan Bukin 	/* Source memory. */
128*85debf7fSRuslan Bukin 
129*85debf7fSRuslan Bukin 	err = bus_dma_tag_create(
130*85debf7fSRuslan Bukin 	    bus_get_dma_tag(sc->dev),
131*85debf7fSRuslan Bukin 	    1024, 0,			/* alignment, boundary */
132*85debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
133*85debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
134*85debf7fSRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
135*85debf7fSRuslan Bukin 	    sc->len, 1,			/* maxsize, nsegments*/
136*85debf7fSRuslan Bukin 	    sc->len, 0,			/* maxsegsize, flags */
137*85debf7fSRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
138*85debf7fSRuslan Bukin 	    &sc->src_dma_tag);
139*85debf7fSRuslan Bukin 	if (err) {
140*85debf7fSRuslan Bukin 		device_printf(sc->dev,
141*85debf7fSRuslan Bukin 		    "%s: Can't create bus_dma tag.\n", __func__);
142*85debf7fSRuslan Bukin 		return (-1);
143*85debf7fSRuslan Bukin 	}
144*85debf7fSRuslan Bukin 
145*85debf7fSRuslan Bukin 	err = bus_dmamem_alloc(sc->src_dma_tag, (void **)&sc->src,
146*85debf7fSRuslan Bukin 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->src_dma_map);
147*85debf7fSRuslan Bukin 	if (err) {
148*85debf7fSRuslan Bukin 		device_printf(sc->dev,
149*85debf7fSRuslan Bukin 		    "%s: Can't allocate memory.\n", __func__);
150*85debf7fSRuslan Bukin 		return (-1);
151*85debf7fSRuslan Bukin 	}
152*85debf7fSRuslan Bukin 
153*85debf7fSRuslan Bukin 	err = bus_dmamap_load(sc->src_dma_tag, sc->src_dma_map, sc->src,
154*85debf7fSRuslan Bukin 	    sc->len, xdmatest_dmamap_cb, &sc->src_phys, BUS_DMA_WAITOK);
155*85debf7fSRuslan Bukin 	if (err) {
156*85debf7fSRuslan Bukin 		device_printf(sc->dev,
157*85debf7fSRuslan Bukin 		    "%s: Can't load DMA map.\n", __func__);
158*85debf7fSRuslan Bukin 		return (-1);
159*85debf7fSRuslan Bukin 	}
160*85debf7fSRuslan Bukin 
161*85debf7fSRuslan Bukin 	/* Destination memory. */
162*85debf7fSRuslan Bukin 
163*85debf7fSRuslan Bukin 	err = bus_dma_tag_create(
164*85debf7fSRuslan Bukin 	    bus_get_dma_tag(sc->dev),
165*85debf7fSRuslan Bukin 	    1024, 0,			/* alignment, boundary */
166*85debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
167*85debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
168*85debf7fSRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
169*85debf7fSRuslan Bukin 	    sc->len, 1,			/* maxsize, nsegments*/
170*85debf7fSRuslan Bukin 	    sc->len, 0,			/* maxsegsize, flags */
171*85debf7fSRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
172*85debf7fSRuslan Bukin 	    &sc->dst_dma_tag);
173*85debf7fSRuslan Bukin 	if (err) {
174*85debf7fSRuslan Bukin 		device_printf(sc->dev,
175*85debf7fSRuslan Bukin 		    "%s: Can't create bus_dma tag.\n", __func__);
176*85debf7fSRuslan Bukin 		return (-1);
177*85debf7fSRuslan Bukin 	}
178*85debf7fSRuslan Bukin 
179*85debf7fSRuslan Bukin 	err = bus_dmamem_alloc(sc->dst_dma_tag, (void **)&sc->dst,
180*85debf7fSRuslan Bukin 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->dst_dma_map);
181*85debf7fSRuslan Bukin 	if (err) {
182*85debf7fSRuslan Bukin 		device_printf(sc->dev,
183*85debf7fSRuslan Bukin 		    "%s: Can't allocate memory.\n", __func__);
184*85debf7fSRuslan Bukin 		return (-1);
185*85debf7fSRuslan Bukin 	}
186*85debf7fSRuslan Bukin 
187*85debf7fSRuslan Bukin 	err = bus_dmamap_load(sc->dst_dma_tag, sc->dst_dma_map, sc->dst,
188*85debf7fSRuslan Bukin 	    sc->len, xdmatest_dmamap_cb, &sc->dst_phys, BUS_DMA_WAITOK);
189*85debf7fSRuslan Bukin 	if (err) {
190*85debf7fSRuslan Bukin 		device_printf(sc->dev,
191*85debf7fSRuslan Bukin 		    "%s: Can't load DMA map.\n", __func__);
192*85debf7fSRuslan Bukin 		return (-1);
193*85debf7fSRuslan Bukin 	}
194*85debf7fSRuslan Bukin 
195*85debf7fSRuslan Bukin 	return (0);
196*85debf7fSRuslan Bukin }
197*85debf7fSRuslan Bukin 
198*85debf7fSRuslan Bukin static int
199*85debf7fSRuslan Bukin xdmatest_test(struct xdmatest_softc *sc)
200*85debf7fSRuslan Bukin {
201*85debf7fSRuslan Bukin 	int err;
202*85debf7fSRuslan Bukin 	int i;
203*85debf7fSRuslan Bukin 
204*85debf7fSRuslan Bukin 	/* Get xDMA controller. */
205*85debf7fSRuslan Bukin 	sc->xdma = xdma_ofw_get(sc->dev, "test");
206*85debf7fSRuslan Bukin 	if (sc->xdma == NULL) {
207*85debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't find xDMA controller.\n");
208*85debf7fSRuslan Bukin 		return (-1);
209*85debf7fSRuslan Bukin 	}
210*85debf7fSRuslan Bukin 
211*85debf7fSRuslan Bukin 	/* Alloc xDMA virtual channel. */
212*85debf7fSRuslan Bukin 	sc->xchan = xdma_channel_alloc(sc->xdma);
213*85debf7fSRuslan Bukin 	if (sc->xchan == NULL) {
214*85debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't alloc virtual DMA channel.\n");
215*85debf7fSRuslan Bukin 		return (-1);
216*85debf7fSRuslan Bukin 	}
217*85debf7fSRuslan Bukin 
218*85debf7fSRuslan Bukin 	/* Setup callback. */
219*85debf7fSRuslan Bukin 	err = xdma_setup_intr(sc->xchan, xdmatest_intr, sc, &sc->ih);
220*85debf7fSRuslan Bukin 	if (err) {
221*85debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't setup xDMA interrupt handler.\n");
222*85debf7fSRuslan Bukin 		return (-1);
223*85debf7fSRuslan Bukin 	}
224*85debf7fSRuslan Bukin 
225*85debf7fSRuslan Bukin 	/* We are going to fill memory. */
226*85debf7fSRuslan Bukin 	bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_PREWRITE);
227*85debf7fSRuslan Bukin 	bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_PREWRITE);
228*85debf7fSRuslan Bukin 
229*85debf7fSRuslan Bukin 	/* Fill memory. */
230*85debf7fSRuslan Bukin 	for (i = 0; i < sc->len; i++) {
231*85debf7fSRuslan Bukin 		sc->src[i] = (i & 0xff);
232*85debf7fSRuslan Bukin 		sc->dst[i] = 0;
233*85debf7fSRuslan Bukin 	}
234*85debf7fSRuslan Bukin 
235*85debf7fSRuslan Bukin 	/* Configure channel for memcpy transfer. */
236*85debf7fSRuslan Bukin 	err = xdma_prep_memcpy(sc->xchan, sc->src_phys, sc->dst_phys, sc->len);
237*85debf7fSRuslan Bukin 	if (err != 0) {
238*85debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't configure virtual channel.\n");
239*85debf7fSRuslan Bukin 		return (-1);
240*85debf7fSRuslan Bukin 	}
241*85debf7fSRuslan Bukin 
242*85debf7fSRuslan Bukin 	/* Start operation. */
243*85debf7fSRuslan Bukin 	xdma_begin(sc->xchan);
244*85debf7fSRuslan Bukin 
245*85debf7fSRuslan Bukin 	return (0);
246*85debf7fSRuslan Bukin }
247*85debf7fSRuslan Bukin 
248*85debf7fSRuslan Bukin static int
249*85debf7fSRuslan Bukin xdmatest_verify(struct xdmatest_softc *sc)
250*85debf7fSRuslan Bukin {
251*85debf7fSRuslan Bukin 	int err;
252*85debf7fSRuslan Bukin 	int i;
253*85debf7fSRuslan Bukin 
254*85debf7fSRuslan Bukin 	/* We have memory updated by DMA controller. */
255*85debf7fSRuslan Bukin 	bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_POSTREAD);
256*85debf7fSRuslan Bukin 	bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_POSTWRITE);
257*85debf7fSRuslan Bukin 
258*85debf7fSRuslan Bukin 	for (i = 0; i < sc->len; i++) {
259*85debf7fSRuslan Bukin 		if (sc->dst[i] != sc->src[i]) {
260*85debf7fSRuslan Bukin 			device_printf(sc->dev,
261*85debf7fSRuslan Bukin 			    "%s: Test failed: iter %d\n", __func__, i);
262*85debf7fSRuslan Bukin 			return (-1);
263*85debf7fSRuslan Bukin 		}
264*85debf7fSRuslan Bukin 	}
265*85debf7fSRuslan Bukin 
266*85debf7fSRuslan Bukin 	err = xdma_channel_free(sc->xchan);
267*85debf7fSRuslan Bukin 	if (err != 0) {
268*85debf7fSRuslan Bukin 		device_printf(sc->dev,
269*85debf7fSRuslan Bukin 		    "%s: Test failed: can't deallocate channel.\n", __func__);
270*85debf7fSRuslan Bukin 		return (-1);
271*85debf7fSRuslan Bukin 	}
272*85debf7fSRuslan Bukin 
273*85debf7fSRuslan Bukin 	err = xdma_put(sc->xdma);
274*85debf7fSRuslan Bukin 	if (err != 0) {
275*85debf7fSRuslan Bukin 		device_printf(sc->dev,
276*85debf7fSRuslan Bukin 		    "%s: Test failed: can't deallocate xDMA.\n", __func__);
277*85debf7fSRuslan Bukin 		return (-1);
278*85debf7fSRuslan Bukin 	}
279*85debf7fSRuslan Bukin 
280*85debf7fSRuslan Bukin 	return (0);
281*85debf7fSRuslan Bukin }
282*85debf7fSRuslan Bukin 
283*85debf7fSRuslan Bukin static void
284*85debf7fSRuslan Bukin xdmatest_worker(void *arg)
285*85debf7fSRuslan Bukin {
286*85debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
287*85debf7fSRuslan Bukin 	int timeout;
288*85debf7fSRuslan Bukin 	int err;
289*85debf7fSRuslan Bukin 
290*85debf7fSRuslan Bukin 	sc = arg;
291*85debf7fSRuslan Bukin 
292*85debf7fSRuslan Bukin 	device_printf(sc->dev, "Worker %d started.\n",
293*85debf7fSRuslan Bukin 	    device_get_unit(sc->dev));
294*85debf7fSRuslan Bukin 
295*85debf7fSRuslan Bukin 	while (1) {
296*85debf7fSRuslan Bukin 		sc->done = 0;
297*85debf7fSRuslan Bukin 
298*85debf7fSRuslan Bukin 		mtx_lock(&sc->mtx);
299*85debf7fSRuslan Bukin 
300*85debf7fSRuslan Bukin 		xdmatest_test(sc);
301*85debf7fSRuslan Bukin 
302*85debf7fSRuslan Bukin 		timeout = 100;
303*85debf7fSRuslan Bukin 
304*85debf7fSRuslan Bukin 		do {
305*85debf7fSRuslan Bukin 			mtx_sleep(sc, &sc->mtx, 0, "xdmatest_wait", hz);
306*85debf7fSRuslan Bukin 		} while (timeout-- && sc->done == 0);
307*85debf7fSRuslan Bukin 
308*85debf7fSRuslan Bukin 		if (timeout != 0) {
309*85debf7fSRuslan Bukin 			err = xdmatest_verify(sc);
310*85debf7fSRuslan Bukin 			if (err == 0) {
311*85debf7fSRuslan Bukin 				/* Test succeeded. */
312*85debf7fSRuslan Bukin 				mtx_unlock(&sc->mtx);
313*85debf7fSRuslan Bukin 				continue;
314*85debf7fSRuslan Bukin 			}
315*85debf7fSRuslan Bukin 		}
316*85debf7fSRuslan Bukin 
317*85debf7fSRuslan Bukin 		mtx_unlock(&sc->mtx);
318*85debf7fSRuslan Bukin 		device_printf(sc->dev,
319*85debf7fSRuslan Bukin 		    "%s: Test failed.\n", __func__);
320*85debf7fSRuslan Bukin 		break;
321*85debf7fSRuslan Bukin 	}
322*85debf7fSRuslan Bukin }
323*85debf7fSRuslan Bukin 
324*85debf7fSRuslan Bukin static void
325*85debf7fSRuslan Bukin xdmatest_delayed_attach(void *arg)
326*85debf7fSRuslan Bukin {
327*85debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
328*85debf7fSRuslan Bukin 
329*85debf7fSRuslan Bukin 	sc = arg;
330*85debf7fSRuslan Bukin 
331*85debf7fSRuslan Bukin 	if (kproc_create(xdmatest_worker, (void *)sc, &sc->newp, 0, 0,
332*85debf7fSRuslan Bukin             "xdmatest_worker") != 0) {
333*85debf7fSRuslan Bukin 		device_printf(sc->dev,
334*85debf7fSRuslan Bukin 		    "%s: Failed to create worker thread.\n", __func__);
335*85debf7fSRuslan Bukin 	}
336*85debf7fSRuslan Bukin 
337*85debf7fSRuslan Bukin 	config_intrhook_disestablish(&sc->config_intrhook);
338*85debf7fSRuslan Bukin }
339*85debf7fSRuslan Bukin 
340*85debf7fSRuslan Bukin static int
341*85debf7fSRuslan Bukin xdmatest_probe(device_t dev)
342*85debf7fSRuslan Bukin {
343*85debf7fSRuslan Bukin 
344*85debf7fSRuslan Bukin 	if (!ofw_bus_status_okay(dev))
345*85debf7fSRuslan Bukin 		return (ENXIO);
346*85debf7fSRuslan Bukin 
347*85debf7fSRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "freebsd,xdma-test"))
348*85debf7fSRuslan Bukin 		return (ENXIO);
349*85debf7fSRuslan Bukin 
350*85debf7fSRuslan Bukin 	device_set_desc(dev, "xDMA test driver");
351*85debf7fSRuslan Bukin 
352*85debf7fSRuslan Bukin 	return (BUS_PROBE_DEFAULT);
353*85debf7fSRuslan Bukin }
354*85debf7fSRuslan Bukin 
355*85debf7fSRuslan Bukin static int
356*85debf7fSRuslan Bukin xdmatest_attach(device_t dev)
357*85debf7fSRuslan Bukin {
358*85debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
359*85debf7fSRuslan Bukin 	int err;
360*85debf7fSRuslan Bukin 
361*85debf7fSRuslan Bukin 	sc = device_get_softc(dev);
362*85debf7fSRuslan Bukin 	sc->dev = dev;
363*85debf7fSRuslan Bukin 
364*85debf7fSRuslan Bukin 	mtx_init(&sc->mtx, device_get_nameunit(dev), "xdmatest", MTX_DEF);
365*85debf7fSRuslan Bukin 
366*85debf7fSRuslan Bukin 	/* Allocate test memory */
367*85debf7fSRuslan Bukin 	err = xdmatest_alloc_test_memory(sc);
368*85debf7fSRuslan Bukin 	if (err != 0) {
369*85debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't allocate test memory.\n");
370*85debf7fSRuslan Bukin 		return (-1);
371*85debf7fSRuslan Bukin 	}
372*85debf7fSRuslan Bukin 
373*85debf7fSRuslan Bukin 	/* We'll run test later, but before / mount. */
374*85debf7fSRuslan Bukin 	sc->config_intrhook.ich_func = xdmatest_delayed_attach;
375*85debf7fSRuslan Bukin 	sc->config_intrhook.ich_arg = sc;
376*85debf7fSRuslan Bukin 	if (config_intrhook_establish(&sc->config_intrhook) != 0)
377*85debf7fSRuslan Bukin 		device_printf(dev, "config_intrhook_establish failed\n");
378*85debf7fSRuslan Bukin 
379*85debf7fSRuslan Bukin 	return (0);
380*85debf7fSRuslan Bukin }
381*85debf7fSRuslan Bukin 
382*85debf7fSRuslan Bukin static int
383*85debf7fSRuslan Bukin xdmatest_detach(device_t dev)
384*85debf7fSRuslan Bukin {
385*85debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
386*85debf7fSRuslan Bukin 
387*85debf7fSRuslan Bukin 	sc = device_get_softc(dev);
388*85debf7fSRuslan Bukin 
389*85debf7fSRuslan Bukin 	bus_dmamap_unload(sc->src_dma_tag, sc->src_dma_map);
390*85debf7fSRuslan Bukin 	bus_dmamem_free(sc->src_dma_tag, sc->src, sc->src_dma_map);
391*85debf7fSRuslan Bukin 	bus_dma_tag_destroy(sc->src_dma_tag);
392*85debf7fSRuslan Bukin 
393*85debf7fSRuslan Bukin 	bus_dmamap_unload(sc->dst_dma_tag, sc->dst_dma_map);
394*85debf7fSRuslan Bukin 	bus_dmamem_free(sc->dst_dma_tag, sc->dst, sc->dst_dma_map);
395*85debf7fSRuslan Bukin 	bus_dma_tag_destroy(sc->dst_dma_tag);
396*85debf7fSRuslan Bukin 
397*85debf7fSRuslan Bukin 	return (0);
398*85debf7fSRuslan Bukin }
399*85debf7fSRuslan Bukin 
400*85debf7fSRuslan Bukin static device_method_t xdmatest_methods[] = {
401*85debf7fSRuslan Bukin 	/* Device interface */
402*85debf7fSRuslan Bukin 	DEVMETHOD(device_probe,			xdmatest_probe),
403*85debf7fSRuslan Bukin 	DEVMETHOD(device_attach,		xdmatest_attach),
404*85debf7fSRuslan Bukin 	DEVMETHOD(device_detach,		xdmatest_detach),
405*85debf7fSRuslan Bukin 
406*85debf7fSRuslan Bukin 	DEVMETHOD_END
407*85debf7fSRuslan Bukin };
408*85debf7fSRuslan Bukin 
409*85debf7fSRuslan Bukin static driver_t xdmatest_driver = {
410*85debf7fSRuslan Bukin 	"xdmatest",
411*85debf7fSRuslan Bukin 	xdmatest_methods,
412*85debf7fSRuslan Bukin 	sizeof(struct xdmatest_softc),
413*85debf7fSRuslan Bukin };
414*85debf7fSRuslan Bukin 
415*85debf7fSRuslan Bukin static devclass_t xdmatest_devclass;
416*85debf7fSRuslan Bukin 
417*85debf7fSRuslan Bukin DRIVER_MODULE(xdmatest, simplebus, xdmatest_driver, xdmatest_devclass, 0, 0);
418