xref: /freebsd/sys/dev/xdma/xdma_fdt_test.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
185debf7fSRuslan Bukin /*-
285debf7fSRuslan Bukin  * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
385debf7fSRuslan Bukin  * All rights reserved.
485debf7fSRuslan Bukin  *
585debf7fSRuslan Bukin  * This software was developed by SRI International and the University of
685debf7fSRuslan Bukin  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
785debf7fSRuslan Bukin  * ("CTSRD"), as part of the DARPA CRASH research programme.
885debf7fSRuslan Bukin  *
985debf7fSRuslan Bukin  * Redistribution and use in source and binary forms, with or without
1085debf7fSRuslan Bukin  * modification, are permitted provided that the following conditions
1185debf7fSRuslan Bukin  * are met:
1285debf7fSRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
1385debf7fSRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
1485debf7fSRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
1585debf7fSRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
1685debf7fSRuslan Bukin  *    documentation and/or other materials provided with the distribution.
1785debf7fSRuslan Bukin  *
1885debf7fSRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1985debf7fSRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2085debf7fSRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2185debf7fSRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2285debf7fSRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2385debf7fSRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2485debf7fSRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2585debf7fSRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2685debf7fSRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2785debf7fSRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2885debf7fSRuslan Bukin  * SUCH DAMAGE.
2985debf7fSRuslan Bukin  */
3085debf7fSRuslan Bukin 
3185debf7fSRuslan Bukin /* xDMA memcpy test driver. */
3285debf7fSRuslan Bukin 
3385debf7fSRuslan Bukin #include <sys/param.h>
3485debf7fSRuslan Bukin #include <sys/systm.h>
3585debf7fSRuslan Bukin #include <sys/conf.h>
3685debf7fSRuslan Bukin #include <sys/bus.h>
3785debf7fSRuslan Bukin #include <sys/kernel.h>
3885debf7fSRuslan Bukin #include <sys/kthread.h>
3985debf7fSRuslan Bukin #include <sys/module.h>
4085debf7fSRuslan Bukin #include <sys/lock.h>
4185debf7fSRuslan Bukin #include <sys/mutex.h>
4285debf7fSRuslan Bukin #include <sys/resource.h>
4385debf7fSRuslan Bukin #include <sys/rman.h>
4485debf7fSRuslan Bukin 
4585debf7fSRuslan Bukin #include <machine/bus.h>
4685debf7fSRuslan Bukin 
4785debf7fSRuslan Bukin #include <dev/xdma/xdma.h>
4885debf7fSRuslan Bukin 
4985debf7fSRuslan Bukin #include <dev/fdt/fdt_common.h>
5085debf7fSRuslan Bukin #include <dev/ofw/ofw_bus.h>
5185debf7fSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
5285debf7fSRuslan Bukin 
5385debf7fSRuslan Bukin /*
5485debf7fSRuslan Bukin  * To use this test add a compatible node to your dts, e.g.
5585debf7fSRuslan Bukin  *
5685debf7fSRuslan Bukin  * 	xdma_test {
5785debf7fSRuslan Bukin  *		compatible = "freebsd,xdma-test";
5885debf7fSRuslan Bukin  *
5985debf7fSRuslan Bukin  * 		dmas = <&dma 0 0 0xffffffff>;
6085debf7fSRuslan Bukin  * 		dma-names = "test";
6185debf7fSRuslan Bukin  *	};
6285debf7fSRuslan Bukin  */
6385debf7fSRuslan Bukin 
6485debf7fSRuslan Bukin struct xdmatest_softc {
6585debf7fSRuslan Bukin 	device_t		dev;
6685debf7fSRuslan Bukin 	xdma_controller_t	*xdma;
6785debf7fSRuslan Bukin 	xdma_channel_t		*xchan;
6885debf7fSRuslan Bukin 	void			*ih;
6985debf7fSRuslan Bukin 	struct intr_config_hook config_intrhook;
7085debf7fSRuslan Bukin 	char			*src;
7185debf7fSRuslan Bukin 	char			*dst;
7285debf7fSRuslan Bukin 	uint32_t		len;
7385debf7fSRuslan Bukin 	uintptr_t		src_phys;
7485debf7fSRuslan Bukin 	uintptr_t		dst_phys;
7585debf7fSRuslan Bukin 	bus_dma_tag_t		src_dma_tag;
7685debf7fSRuslan Bukin 	bus_dmamap_t		src_dma_map;
7785debf7fSRuslan Bukin 	bus_dma_tag_t		dst_dma_tag;
7885debf7fSRuslan Bukin 	bus_dmamap_t		dst_dma_map;
7985debf7fSRuslan Bukin 	struct mtx		mtx;
8085debf7fSRuslan Bukin 	int			done;
8185debf7fSRuslan Bukin 	struct proc		*newp;
823d5b3b0aSRuslan Bukin 	struct xdma_request	req;
8385debf7fSRuslan Bukin };
8485debf7fSRuslan Bukin 
8585debf7fSRuslan Bukin static int xdmatest_probe(device_t dev);
8685debf7fSRuslan Bukin static int xdmatest_attach(device_t dev);
8785debf7fSRuslan Bukin static int xdmatest_detach(device_t dev);
8885debf7fSRuslan Bukin 
8985debf7fSRuslan Bukin static int
xdmatest_intr(void * arg)9085debf7fSRuslan Bukin xdmatest_intr(void *arg)
9185debf7fSRuslan Bukin {
9285debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
9385debf7fSRuslan Bukin 
9485debf7fSRuslan Bukin 	sc = arg;
9585debf7fSRuslan Bukin 
9685debf7fSRuslan Bukin 	sc->done = 1;
9785debf7fSRuslan Bukin 
9885debf7fSRuslan Bukin 	mtx_lock(&sc->mtx);
9985debf7fSRuslan Bukin 	wakeup(sc);
10085debf7fSRuslan Bukin 	mtx_unlock(&sc->mtx);
10185debf7fSRuslan Bukin 
10285debf7fSRuslan Bukin 	return (0);
10385debf7fSRuslan Bukin }
10485debf7fSRuslan Bukin 
10585debf7fSRuslan Bukin static void
xdmatest_dmamap_cb(void * arg,bus_dma_segment_t * segs,int nseg,int err)10685debf7fSRuslan Bukin xdmatest_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
10785debf7fSRuslan Bukin {
10885debf7fSRuslan Bukin 	bus_addr_t *addr;
10985debf7fSRuslan Bukin 
11085debf7fSRuslan Bukin 	if (err)
11185debf7fSRuslan Bukin 		return;
11285debf7fSRuslan Bukin 
11385debf7fSRuslan Bukin 	addr = (bus_addr_t*)arg;
11485debf7fSRuslan Bukin 	*addr = segs[0].ds_addr;
11585debf7fSRuslan Bukin }
11685debf7fSRuslan Bukin 
11785debf7fSRuslan Bukin static int
xdmatest_alloc_test_memory(struct xdmatest_softc * sc)11885debf7fSRuslan Bukin xdmatest_alloc_test_memory(struct xdmatest_softc *sc)
11985debf7fSRuslan Bukin {
12085debf7fSRuslan Bukin 	int err;
12185debf7fSRuslan Bukin 
12285debf7fSRuslan Bukin 	sc->len = (0x1000000 - 8); /* 16mb */
12385debf7fSRuslan Bukin 	sc->len = 8;
12485debf7fSRuslan Bukin 
12585debf7fSRuslan Bukin 	/* Source memory. */
12685debf7fSRuslan Bukin 
12785debf7fSRuslan Bukin 	err = bus_dma_tag_create(
12885debf7fSRuslan Bukin 	    bus_get_dma_tag(sc->dev),
12985debf7fSRuslan Bukin 	    1024, 0,			/* alignment, boundary */
13085debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
13185debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
13285debf7fSRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
13385debf7fSRuslan Bukin 	    sc->len, 1,			/* maxsize, nsegments*/
13485debf7fSRuslan Bukin 	    sc->len, 0,			/* maxsegsize, flags */
13585debf7fSRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
13685debf7fSRuslan Bukin 	    &sc->src_dma_tag);
13785debf7fSRuslan Bukin 	if (err) {
13885debf7fSRuslan Bukin 		device_printf(sc->dev,
13985debf7fSRuslan Bukin 		    "%s: Can't create bus_dma tag.\n", __func__);
14085debf7fSRuslan Bukin 		return (-1);
14185debf7fSRuslan Bukin 	}
14285debf7fSRuslan Bukin 
14385debf7fSRuslan Bukin 	err = bus_dmamem_alloc(sc->src_dma_tag, (void **)&sc->src,
14485debf7fSRuslan Bukin 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->src_dma_map);
14585debf7fSRuslan Bukin 	if (err) {
14685debf7fSRuslan Bukin 		device_printf(sc->dev,
14785debf7fSRuslan Bukin 		    "%s: Can't allocate memory.\n", __func__);
14885debf7fSRuslan Bukin 		return (-1);
14985debf7fSRuslan Bukin 	}
15085debf7fSRuslan Bukin 
15185debf7fSRuslan Bukin 	err = bus_dmamap_load(sc->src_dma_tag, sc->src_dma_map, sc->src,
15285debf7fSRuslan Bukin 	    sc->len, xdmatest_dmamap_cb, &sc->src_phys, BUS_DMA_WAITOK);
15385debf7fSRuslan Bukin 	if (err) {
15485debf7fSRuslan Bukin 		device_printf(sc->dev,
15585debf7fSRuslan Bukin 		    "%s: Can't load DMA map.\n", __func__);
15685debf7fSRuslan Bukin 		return (-1);
15785debf7fSRuslan Bukin 	}
15885debf7fSRuslan Bukin 
15985debf7fSRuslan Bukin 	/* Destination memory. */
16085debf7fSRuslan Bukin 
16185debf7fSRuslan Bukin 	err = bus_dma_tag_create(
16285debf7fSRuslan Bukin 	    bus_get_dma_tag(sc->dev),
16385debf7fSRuslan Bukin 	    1024, 0,			/* alignment, boundary */
16485debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
16585debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
16685debf7fSRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
16785debf7fSRuslan Bukin 	    sc->len, 1,			/* maxsize, nsegments*/
16885debf7fSRuslan Bukin 	    sc->len, 0,			/* maxsegsize, flags */
16985debf7fSRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
17085debf7fSRuslan Bukin 	    &sc->dst_dma_tag);
17185debf7fSRuslan Bukin 	if (err) {
17285debf7fSRuslan Bukin 		device_printf(sc->dev,
17385debf7fSRuslan Bukin 		    "%s: Can't create bus_dma tag.\n", __func__);
17485debf7fSRuslan Bukin 		return (-1);
17585debf7fSRuslan Bukin 	}
17685debf7fSRuslan Bukin 
17785debf7fSRuslan Bukin 	err = bus_dmamem_alloc(sc->dst_dma_tag, (void **)&sc->dst,
17885debf7fSRuslan Bukin 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->dst_dma_map);
17985debf7fSRuslan Bukin 	if (err) {
18085debf7fSRuslan Bukin 		device_printf(sc->dev,
18185debf7fSRuslan Bukin 		    "%s: Can't allocate memory.\n", __func__);
18285debf7fSRuslan Bukin 		return (-1);
18385debf7fSRuslan Bukin 	}
18485debf7fSRuslan Bukin 
18585debf7fSRuslan Bukin 	err = bus_dmamap_load(sc->dst_dma_tag, sc->dst_dma_map, sc->dst,
18685debf7fSRuslan Bukin 	    sc->len, xdmatest_dmamap_cb, &sc->dst_phys, BUS_DMA_WAITOK);
18785debf7fSRuslan Bukin 	if (err) {
18885debf7fSRuslan Bukin 		device_printf(sc->dev,
18985debf7fSRuslan Bukin 		    "%s: Can't load DMA map.\n", __func__);
19085debf7fSRuslan Bukin 		return (-1);
19185debf7fSRuslan Bukin 	}
19285debf7fSRuslan Bukin 
19385debf7fSRuslan Bukin 	return (0);
19485debf7fSRuslan Bukin }
19585debf7fSRuslan Bukin 
19685debf7fSRuslan Bukin static int
xdmatest_test(struct xdmatest_softc * sc)19785debf7fSRuslan Bukin xdmatest_test(struct xdmatest_softc *sc)
19885debf7fSRuslan Bukin {
19985debf7fSRuslan Bukin 	int err;
20085debf7fSRuslan Bukin 	int i;
20185debf7fSRuslan Bukin 
20285debf7fSRuslan Bukin 	/* Get xDMA controller. */
20385debf7fSRuslan Bukin 	sc->xdma = xdma_ofw_get(sc->dev, "test");
20485debf7fSRuslan Bukin 	if (sc->xdma == NULL) {
20585debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't find xDMA controller.\n");
20685debf7fSRuslan Bukin 		return (-1);
20785debf7fSRuslan Bukin 	}
20885debf7fSRuslan Bukin 
20985debf7fSRuslan Bukin 	/* Alloc xDMA virtual channel. */
21085debf7fSRuslan Bukin 	sc->xchan = xdma_channel_alloc(sc->xdma);
21185debf7fSRuslan Bukin 	if (sc->xchan == NULL) {
21285debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't alloc virtual DMA channel.\n");
21385debf7fSRuslan Bukin 		return (-1);
21485debf7fSRuslan Bukin 	}
21585debf7fSRuslan Bukin 
21685debf7fSRuslan Bukin 	/* Setup callback. */
217d987842dSRuslan Bukin 	err = xdma_setup_intr(sc->xchan, 0, xdmatest_intr, sc, &sc->ih);
21885debf7fSRuslan Bukin 	if (err) {
21985debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't setup xDMA interrupt handler.\n");
22085debf7fSRuslan Bukin 		return (-1);
22185debf7fSRuslan Bukin 	}
22285debf7fSRuslan Bukin 
22385debf7fSRuslan Bukin 	/* We are going to fill memory. */
22485debf7fSRuslan Bukin 	bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_PREWRITE);
22585debf7fSRuslan Bukin 	bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_PREWRITE);
22685debf7fSRuslan Bukin 
22785debf7fSRuslan Bukin 	/* Fill memory. */
22885debf7fSRuslan Bukin 	for (i = 0; i < sc->len; i++) {
22985debf7fSRuslan Bukin 		sc->src[i] = (i & 0xff);
23085debf7fSRuslan Bukin 		sc->dst[i] = 0;
23185debf7fSRuslan Bukin 	}
23285debf7fSRuslan Bukin 
2333d5b3b0aSRuslan Bukin 	sc->req.type = XR_TYPE_PHYS_ADDR;
2343d5b3b0aSRuslan Bukin 	sc->req.direction = XDMA_MEM_TO_MEM;
2353d5b3b0aSRuslan Bukin 	sc->req.src_addr = sc->src_phys;
2363d5b3b0aSRuslan Bukin 	sc->req.dst_addr = sc->dst_phys;
2373d5b3b0aSRuslan Bukin 	sc->req.src_width = 4;
2383d5b3b0aSRuslan Bukin 	sc->req.dst_width = 4;
2393d5b3b0aSRuslan Bukin 	sc->req.block_len = sc->len;
2403d5b3b0aSRuslan Bukin 	sc->req.block_num = 1;
2413d5b3b0aSRuslan Bukin 
2423d5b3b0aSRuslan Bukin 	err = xdma_request(sc->xchan, sc->src_phys, sc->dst_phys, sc->len);
24385debf7fSRuslan Bukin 	if (err != 0) {
24485debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't configure virtual channel.\n");
24585debf7fSRuslan Bukin 		return (-1);
24685debf7fSRuslan Bukin 	}
24785debf7fSRuslan Bukin 
24885debf7fSRuslan Bukin 	/* Start operation. */
24985debf7fSRuslan Bukin 	xdma_begin(sc->xchan);
25085debf7fSRuslan Bukin 
25185debf7fSRuslan Bukin 	return (0);
25285debf7fSRuslan Bukin }
25385debf7fSRuslan Bukin 
25485debf7fSRuslan Bukin static int
xdmatest_verify(struct xdmatest_softc * sc)25585debf7fSRuslan Bukin xdmatest_verify(struct xdmatest_softc *sc)
25685debf7fSRuslan Bukin {
25785debf7fSRuslan Bukin 	int err;
25885debf7fSRuslan Bukin 	int i;
25985debf7fSRuslan Bukin 
26085debf7fSRuslan Bukin 	/* We have memory updated by DMA controller. */
26185debf7fSRuslan Bukin 	bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_POSTREAD);
26285debf7fSRuslan Bukin 	bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_POSTWRITE);
26385debf7fSRuslan Bukin 
26485debf7fSRuslan Bukin 	for (i = 0; i < sc->len; i++) {
26585debf7fSRuslan Bukin 		if (sc->dst[i] != sc->src[i]) {
26685debf7fSRuslan Bukin 			device_printf(sc->dev,
26785debf7fSRuslan Bukin 			    "%s: Test failed: iter %d\n", __func__, i);
26885debf7fSRuslan Bukin 			return (-1);
26985debf7fSRuslan Bukin 		}
27085debf7fSRuslan Bukin 	}
27185debf7fSRuslan Bukin 
27285debf7fSRuslan Bukin 	err = xdma_channel_free(sc->xchan);
27385debf7fSRuslan Bukin 	if (err != 0) {
27485debf7fSRuslan Bukin 		device_printf(sc->dev,
27585debf7fSRuslan Bukin 		    "%s: Test failed: can't deallocate channel.\n", __func__);
27685debf7fSRuslan Bukin 		return (-1);
27785debf7fSRuslan Bukin 	}
27885debf7fSRuslan Bukin 
27985debf7fSRuslan Bukin 	err = xdma_put(sc->xdma);
28085debf7fSRuslan Bukin 	if (err != 0) {
28185debf7fSRuslan Bukin 		device_printf(sc->dev,
28285debf7fSRuslan Bukin 		    "%s: Test failed: can't deallocate xDMA.\n", __func__);
28385debf7fSRuslan Bukin 		return (-1);
28485debf7fSRuslan Bukin 	}
28585debf7fSRuslan Bukin 
28685debf7fSRuslan Bukin 	return (0);
28785debf7fSRuslan Bukin }
28885debf7fSRuslan Bukin 
28985debf7fSRuslan Bukin static void
xdmatest_worker(void * arg)29085debf7fSRuslan Bukin xdmatest_worker(void *arg)
29185debf7fSRuslan Bukin {
29285debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
29385debf7fSRuslan Bukin 	int timeout;
29485debf7fSRuslan Bukin 	int err;
29585debf7fSRuslan Bukin 
29685debf7fSRuslan Bukin 	sc = arg;
29785debf7fSRuslan Bukin 
29885debf7fSRuslan Bukin 	device_printf(sc->dev, "Worker %d started.\n",
29985debf7fSRuslan Bukin 	    device_get_unit(sc->dev));
30085debf7fSRuslan Bukin 
30185debf7fSRuslan Bukin 	while (1) {
30285debf7fSRuslan Bukin 		sc->done = 0;
30385debf7fSRuslan Bukin 
30485debf7fSRuslan Bukin 		mtx_lock(&sc->mtx);
30585debf7fSRuslan Bukin 
3063d5b3b0aSRuslan Bukin 		if (xdmatest_test(sc) != 0) {
3073d5b3b0aSRuslan Bukin 			mtx_unlock(&sc->mtx);
3083d5b3b0aSRuslan Bukin 			device_printf(sc->dev,
3093d5b3b0aSRuslan Bukin 			    "%s: Test failed.\n", __func__);
3103d5b3b0aSRuslan Bukin 			break;
3113d5b3b0aSRuslan Bukin 		}
31285debf7fSRuslan Bukin 
31385debf7fSRuslan Bukin 		timeout = 100;
31485debf7fSRuslan Bukin 
31585debf7fSRuslan Bukin 		do {
31685debf7fSRuslan Bukin 			mtx_sleep(sc, &sc->mtx, 0, "xdmatest_wait", hz);
31785debf7fSRuslan Bukin 		} while (timeout-- && sc->done == 0);
31885debf7fSRuslan Bukin 
31985debf7fSRuslan Bukin 		if (timeout != 0) {
32085debf7fSRuslan Bukin 			err = xdmatest_verify(sc);
32185debf7fSRuslan Bukin 			if (err == 0) {
32285debf7fSRuslan Bukin 				/* Test succeeded. */
32385debf7fSRuslan Bukin 				mtx_unlock(&sc->mtx);
32485debf7fSRuslan Bukin 				continue;
32585debf7fSRuslan Bukin 			}
32685debf7fSRuslan Bukin 		}
32785debf7fSRuslan Bukin 
32885debf7fSRuslan Bukin 		mtx_unlock(&sc->mtx);
32985debf7fSRuslan Bukin 		device_printf(sc->dev,
33085debf7fSRuslan Bukin 		    "%s: Test failed.\n", __func__);
33185debf7fSRuslan Bukin 		break;
33285debf7fSRuslan Bukin 	}
33385debf7fSRuslan Bukin }
33485debf7fSRuslan Bukin 
33585debf7fSRuslan Bukin static void
xdmatest_delayed_attach(void * arg)33685debf7fSRuslan Bukin xdmatest_delayed_attach(void *arg)
33785debf7fSRuslan Bukin {
33885debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
33985debf7fSRuslan Bukin 
34085debf7fSRuslan Bukin 	sc = arg;
34185debf7fSRuslan Bukin 
34285debf7fSRuslan Bukin 	if (kproc_create(xdmatest_worker, (void *)sc, &sc->newp, 0, 0,
34385debf7fSRuslan Bukin             "xdmatest_worker") != 0) {
34485debf7fSRuslan Bukin 		device_printf(sc->dev,
34585debf7fSRuslan Bukin 		    "%s: Failed to create worker thread.\n", __func__);
34685debf7fSRuslan Bukin 	}
34785debf7fSRuslan Bukin 
34885debf7fSRuslan Bukin 	config_intrhook_disestablish(&sc->config_intrhook);
34985debf7fSRuslan Bukin }
35085debf7fSRuslan Bukin 
35185debf7fSRuslan Bukin static int
xdmatest_probe(device_t dev)35285debf7fSRuslan Bukin xdmatest_probe(device_t dev)
35385debf7fSRuslan Bukin {
35485debf7fSRuslan Bukin 
35585debf7fSRuslan Bukin 	if (!ofw_bus_status_okay(dev))
35685debf7fSRuslan Bukin 		return (ENXIO);
35785debf7fSRuslan Bukin 
35885debf7fSRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "freebsd,xdma-test"))
35985debf7fSRuslan Bukin 		return (ENXIO);
36085debf7fSRuslan Bukin 
36185debf7fSRuslan Bukin 	device_set_desc(dev, "xDMA test driver");
36285debf7fSRuslan Bukin 
36385debf7fSRuslan Bukin 	return (BUS_PROBE_DEFAULT);
36485debf7fSRuslan Bukin }
36585debf7fSRuslan Bukin 
36685debf7fSRuslan Bukin static int
xdmatest_attach(device_t dev)36785debf7fSRuslan Bukin xdmatest_attach(device_t dev)
36885debf7fSRuslan Bukin {
36985debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
37085debf7fSRuslan Bukin 	int err;
37185debf7fSRuslan Bukin 
37285debf7fSRuslan Bukin 	sc = device_get_softc(dev);
37385debf7fSRuslan Bukin 	sc->dev = dev;
37485debf7fSRuslan Bukin 
37585debf7fSRuslan Bukin 	mtx_init(&sc->mtx, device_get_nameunit(dev), "xdmatest", MTX_DEF);
37685debf7fSRuslan Bukin 
37785debf7fSRuslan Bukin 	/* Allocate test memory */
37885debf7fSRuslan Bukin 	err = xdmatest_alloc_test_memory(sc);
37985debf7fSRuslan Bukin 	if (err != 0) {
38085debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't allocate test memory.\n");
38185debf7fSRuslan Bukin 		return (-1);
38285debf7fSRuslan Bukin 	}
38385debf7fSRuslan Bukin 
38485debf7fSRuslan Bukin 	/* We'll run test later, but before / mount. */
38585debf7fSRuslan Bukin 	sc->config_intrhook.ich_func = xdmatest_delayed_attach;
38685debf7fSRuslan Bukin 	sc->config_intrhook.ich_arg = sc;
38785debf7fSRuslan Bukin 	if (config_intrhook_establish(&sc->config_intrhook) != 0)
38885debf7fSRuslan Bukin 		device_printf(dev, "config_intrhook_establish failed\n");
38985debf7fSRuslan Bukin 
39085debf7fSRuslan Bukin 	return (0);
39185debf7fSRuslan Bukin }
39285debf7fSRuslan Bukin 
39385debf7fSRuslan Bukin static int
xdmatest_detach(device_t dev)39485debf7fSRuslan Bukin xdmatest_detach(device_t dev)
39585debf7fSRuslan Bukin {
39685debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
39785debf7fSRuslan Bukin 
39885debf7fSRuslan Bukin 	sc = device_get_softc(dev);
39985debf7fSRuslan Bukin 
40085debf7fSRuslan Bukin 	bus_dmamap_unload(sc->src_dma_tag, sc->src_dma_map);
40185debf7fSRuslan Bukin 	bus_dmamem_free(sc->src_dma_tag, sc->src, sc->src_dma_map);
40285debf7fSRuslan Bukin 	bus_dma_tag_destroy(sc->src_dma_tag);
40385debf7fSRuslan Bukin 
40485debf7fSRuslan Bukin 	bus_dmamap_unload(sc->dst_dma_tag, sc->dst_dma_map);
40585debf7fSRuslan Bukin 	bus_dmamem_free(sc->dst_dma_tag, sc->dst, sc->dst_dma_map);
40685debf7fSRuslan Bukin 	bus_dma_tag_destroy(sc->dst_dma_tag);
40785debf7fSRuslan Bukin 
40885debf7fSRuslan Bukin 	return (0);
40985debf7fSRuslan Bukin }
41085debf7fSRuslan Bukin 
41185debf7fSRuslan Bukin static device_method_t xdmatest_methods[] = {
41285debf7fSRuslan Bukin 	/* Device interface */
41385debf7fSRuslan Bukin 	DEVMETHOD(device_probe,			xdmatest_probe),
41485debf7fSRuslan Bukin 	DEVMETHOD(device_attach,		xdmatest_attach),
41585debf7fSRuslan Bukin 	DEVMETHOD(device_detach,		xdmatest_detach),
41685debf7fSRuslan Bukin 
41785debf7fSRuslan Bukin 	DEVMETHOD_END
41885debf7fSRuslan Bukin };
41985debf7fSRuslan Bukin 
42085debf7fSRuslan Bukin static driver_t xdmatest_driver = {
42185debf7fSRuslan Bukin 	"xdmatest",
42285debf7fSRuslan Bukin 	xdmatest_methods,
42385debf7fSRuslan Bukin 	sizeof(struct xdmatest_softc),
42485debf7fSRuslan Bukin };
42585debf7fSRuslan Bukin 
426*a3f08403SJohn Baldwin DRIVER_MODULE(xdmatest, simplebus, xdmatest_driver, 0, 0);
427