xref: /freebsd/sys/dev/xdma/xdma_fdt_test.c (revision d987842d1edea3de3bad34d8bdc4b1b34cff48a9)
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/cdefs.h>
3485debf7fSRuslan Bukin __FBSDID("$FreeBSD$");
3585debf7fSRuslan Bukin 
3685debf7fSRuslan Bukin #include <sys/param.h>
3785debf7fSRuslan Bukin #include <sys/systm.h>
3885debf7fSRuslan Bukin #include <sys/conf.h>
3985debf7fSRuslan Bukin #include <sys/bus.h>
4085debf7fSRuslan Bukin #include <sys/kernel.h>
4185debf7fSRuslan Bukin #include <sys/kthread.h>
4285debf7fSRuslan Bukin #include <sys/module.h>
4385debf7fSRuslan Bukin #include <sys/lock.h>
4485debf7fSRuslan Bukin #include <sys/mutex.h>
4585debf7fSRuslan Bukin #include <sys/resource.h>
4685debf7fSRuslan Bukin #include <sys/rman.h>
4785debf7fSRuslan Bukin 
4885debf7fSRuslan Bukin #include <machine/bus.h>
4985debf7fSRuslan Bukin 
5085debf7fSRuslan Bukin #include <dev/xdma/xdma.h>
5185debf7fSRuslan Bukin 
5285debf7fSRuslan Bukin #include <dev/fdt/fdt_common.h>
5385debf7fSRuslan Bukin #include <dev/ofw/ofw_bus.h>
5485debf7fSRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
5585debf7fSRuslan Bukin 
5685debf7fSRuslan Bukin /*
5785debf7fSRuslan Bukin  * To use this test add a compatible node to your dts, e.g.
5885debf7fSRuslan Bukin  *
5985debf7fSRuslan Bukin  * 	xdma_test {
6085debf7fSRuslan Bukin  *		compatible = "freebsd,xdma-test";
6185debf7fSRuslan Bukin  *
6285debf7fSRuslan Bukin  * 		dmas = <&dma 0 0 0xffffffff>;
6385debf7fSRuslan Bukin  * 		dma-names = "test";
6485debf7fSRuslan Bukin  *	};
6585debf7fSRuslan Bukin  */
6685debf7fSRuslan Bukin 
6785debf7fSRuslan Bukin struct xdmatest_softc {
6885debf7fSRuslan Bukin 	device_t		dev;
6985debf7fSRuslan Bukin 	xdma_controller_t	*xdma;
7085debf7fSRuslan Bukin 	xdma_channel_t		*xchan;
7185debf7fSRuslan Bukin 	void			*ih;
7285debf7fSRuslan Bukin 	struct intr_config_hook config_intrhook;
7385debf7fSRuslan Bukin 	char			*src;
7485debf7fSRuslan Bukin 	char			*dst;
7585debf7fSRuslan Bukin 	uint32_t		len;
7685debf7fSRuslan Bukin 	uintptr_t		src_phys;
7785debf7fSRuslan Bukin 	uintptr_t		dst_phys;
7885debf7fSRuslan Bukin 	bus_dma_tag_t		src_dma_tag;
7985debf7fSRuslan Bukin 	bus_dmamap_t		src_dma_map;
8085debf7fSRuslan Bukin 	bus_dma_tag_t		dst_dma_tag;
8185debf7fSRuslan Bukin 	bus_dmamap_t		dst_dma_map;
8285debf7fSRuslan Bukin 	struct mtx		mtx;
8385debf7fSRuslan Bukin 	int			done;
8485debf7fSRuslan Bukin 	struct proc		*newp;
853d5b3b0aSRuslan Bukin 	struct xdma_request	req;
8685debf7fSRuslan Bukin };
8785debf7fSRuslan Bukin 
8885debf7fSRuslan Bukin static int xdmatest_probe(device_t dev);
8985debf7fSRuslan Bukin static int xdmatest_attach(device_t dev);
9085debf7fSRuslan Bukin static int xdmatest_detach(device_t dev);
9185debf7fSRuslan Bukin 
9285debf7fSRuslan Bukin static int
9385debf7fSRuslan Bukin xdmatest_intr(void *arg)
9485debf7fSRuslan Bukin {
9585debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
9685debf7fSRuslan Bukin 
9785debf7fSRuslan Bukin 	sc = arg;
9885debf7fSRuslan Bukin 
9985debf7fSRuslan Bukin 	sc->done = 1;
10085debf7fSRuslan Bukin 
10185debf7fSRuslan Bukin 	mtx_lock(&sc->mtx);
10285debf7fSRuslan Bukin 	wakeup(sc);
10385debf7fSRuslan Bukin 	mtx_unlock(&sc->mtx);
10485debf7fSRuslan Bukin 
10585debf7fSRuslan Bukin 	return (0);
10685debf7fSRuslan Bukin }
10785debf7fSRuslan Bukin 
10885debf7fSRuslan Bukin static void
10985debf7fSRuslan Bukin xdmatest_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
11085debf7fSRuslan Bukin {
11185debf7fSRuslan Bukin 	bus_addr_t *addr;
11285debf7fSRuslan Bukin 
11385debf7fSRuslan Bukin 	if (err)
11485debf7fSRuslan Bukin 		return;
11585debf7fSRuslan Bukin 
11685debf7fSRuslan Bukin 	addr = (bus_addr_t*)arg;
11785debf7fSRuslan Bukin 	*addr = segs[0].ds_addr;
11885debf7fSRuslan Bukin }
11985debf7fSRuslan Bukin 
12085debf7fSRuslan Bukin static int
12185debf7fSRuslan Bukin xdmatest_alloc_test_memory(struct xdmatest_softc *sc)
12285debf7fSRuslan Bukin {
12385debf7fSRuslan Bukin 	int err;
12485debf7fSRuslan Bukin 
12585debf7fSRuslan Bukin 	sc->len = (0x1000000 - 8); /* 16mb */
12685debf7fSRuslan Bukin 	sc->len = 8;
12785debf7fSRuslan Bukin 
12885debf7fSRuslan Bukin 	/* Source memory. */
12985debf7fSRuslan Bukin 
13085debf7fSRuslan Bukin 	err = bus_dma_tag_create(
13185debf7fSRuslan Bukin 	    bus_get_dma_tag(sc->dev),
13285debf7fSRuslan Bukin 	    1024, 0,			/* alignment, boundary */
13385debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
13485debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
13585debf7fSRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
13685debf7fSRuslan Bukin 	    sc->len, 1,			/* maxsize, nsegments*/
13785debf7fSRuslan Bukin 	    sc->len, 0,			/* maxsegsize, flags */
13885debf7fSRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
13985debf7fSRuslan Bukin 	    &sc->src_dma_tag);
14085debf7fSRuslan Bukin 	if (err) {
14185debf7fSRuslan Bukin 		device_printf(sc->dev,
14285debf7fSRuslan Bukin 		    "%s: Can't create bus_dma tag.\n", __func__);
14385debf7fSRuslan Bukin 		return (-1);
14485debf7fSRuslan Bukin 	}
14585debf7fSRuslan Bukin 
14685debf7fSRuslan Bukin 	err = bus_dmamem_alloc(sc->src_dma_tag, (void **)&sc->src,
14785debf7fSRuslan Bukin 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->src_dma_map);
14885debf7fSRuslan Bukin 	if (err) {
14985debf7fSRuslan Bukin 		device_printf(sc->dev,
15085debf7fSRuslan Bukin 		    "%s: Can't allocate memory.\n", __func__);
15185debf7fSRuslan Bukin 		return (-1);
15285debf7fSRuslan Bukin 	}
15385debf7fSRuslan Bukin 
15485debf7fSRuslan Bukin 	err = bus_dmamap_load(sc->src_dma_tag, sc->src_dma_map, sc->src,
15585debf7fSRuslan Bukin 	    sc->len, xdmatest_dmamap_cb, &sc->src_phys, BUS_DMA_WAITOK);
15685debf7fSRuslan Bukin 	if (err) {
15785debf7fSRuslan Bukin 		device_printf(sc->dev,
15885debf7fSRuslan Bukin 		    "%s: Can't load DMA map.\n", __func__);
15985debf7fSRuslan Bukin 		return (-1);
16085debf7fSRuslan Bukin 	}
16185debf7fSRuslan Bukin 
16285debf7fSRuslan Bukin 	/* Destination memory. */
16385debf7fSRuslan Bukin 
16485debf7fSRuslan Bukin 	err = bus_dma_tag_create(
16585debf7fSRuslan Bukin 	    bus_get_dma_tag(sc->dev),
16685debf7fSRuslan Bukin 	    1024, 0,			/* alignment, boundary */
16785debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
16885debf7fSRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
16985debf7fSRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
17085debf7fSRuslan Bukin 	    sc->len, 1,			/* maxsize, nsegments*/
17185debf7fSRuslan Bukin 	    sc->len, 0,			/* maxsegsize, flags */
17285debf7fSRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
17385debf7fSRuslan Bukin 	    &sc->dst_dma_tag);
17485debf7fSRuslan Bukin 	if (err) {
17585debf7fSRuslan Bukin 		device_printf(sc->dev,
17685debf7fSRuslan Bukin 		    "%s: Can't create bus_dma tag.\n", __func__);
17785debf7fSRuslan Bukin 		return (-1);
17885debf7fSRuslan Bukin 	}
17985debf7fSRuslan Bukin 
18085debf7fSRuslan Bukin 	err = bus_dmamem_alloc(sc->dst_dma_tag, (void **)&sc->dst,
18185debf7fSRuslan Bukin 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->dst_dma_map);
18285debf7fSRuslan Bukin 	if (err) {
18385debf7fSRuslan Bukin 		device_printf(sc->dev,
18485debf7fSRuslan Bukin 		    "%s: Can't allocate memory.\n", __func__);
18585debf7fSRuslan Bukin 		return (-1);
18685debf7fSRuslan Bukin 	}
18785debf7fSRuslan Bukin 
18885debf7fSRuslan Bukin 	err = bus_dmamap_load(sc->dst_dma_tag, sc->dst_dma_map, sc->dst,
18985debf7fSRuslan Bukin 	    sc->len, xdmatest_dmamap_cb, &sc->dst_phys, BUS_DMA_WAITOK);
19085debf7fSRuslan Bukin 	if (err) {
19185debf7fSRuslan Bukin 		device_printf(sc->dev,
19285debf7fSRuslan Bukin 		    "%s: Can't load DMA map.\n", __func__);
19385debf7fSRuslan Bukin 		return (-1);
19485debf7fSRuslan Bukin 	}
19585debf7fSRuslan Bukin 
19685debf7fSRuslan Bukin 	return (0);
19785debf7fSRuslan Bukin }
19885debf7fSRuslan Bukin 
19985debf7fSRuslan Bukin static int
20085debf7fSRuslan Bukin xdmatest_test(struct xdmatest_softc *sc)
20185debf7fSRuslan Bukin {
20285debf7fSRuslan Bukin 	int err;
20385debf7fSRuslan Bukin 	int i;
20485debf7fSRuslan Bukin 
20585debf7fSRuslan Bukin 	/* Get xDMA controller. */
20685debf7fSRuslan Bukin 	sc->xdma = xdma_ofw_get(sc->dev, "test");
20785debf7fSRuslan Bukin 	if (sc->xdma == NULL) {
20885debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't find xDMA controller.\n");
20985debf7fSRuslan Bukin 		return (-1);
21085debf7fSRuslan Bukin 	}
21185debf7fSRuslan Bukin 
21285debf7fSRuslan Bukin 	/* Alloc xDMA virtual channel. */
21385debf7fSRuslan Bukin 	sc->xchan = xdma_channel_alloc(sc->xdma);
21485debf7fSRuslan Bukin 	if (sc->xchan == NULL) {
21585debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't alloc virtual DMA channel.\n");
21685debf7fSRuslan Bukin 		return (-1);
21785debf7fSRuslan Bukin 	}
21885debf7fSRuslan Bukin 
21985debf7fSRuslan Bukin 	/* Setup callback. */
220*d987842dSRuslan Bukin 	err = xdma_setup_intr(sc->xchan, 0, xdmatest_intr, sc, &sc->ih);
22185debf7fSRuslan Bukin 	if (err) {
22285debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't setup xDMA interrupt handler.\n");
22385debf7fSRuslan Bukin 		return (-1);
22485debf7fSRuslan Bukin 	}
22585debf7fSRuslan Bukin 
22685debf7fSRuslan Bukin 	/* We are going to fill memory. */
22785debf7fSRuslan Bukin 	bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_PREWRITE);
22885debf7fSRuslan Bukin 	bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_PREWRITE);
22985debf7fSRuslan Bukin 
23085debf7fSRuslan Bukin 	/* Fill memory. */
23185debf7fSRuslan Bukin 	for (i = 0; i < sc->len; i++) {
23285debf7fSRuslan Bukin 		sc->src[i] = (i & 0xff);
23385debf7fSRuslan Bukin 		sc->dst[i] = 0;
23485debf7fSRuslan Bukin 	}
23585debf7fSRuslan Bukin 
2363d5b3b0aSRuslan Bukin 	sc->req.type = XR_TYPE_PHYS_ADDR;
2373d5b3b0aSRuslan Bukin 	sc->req.direction = XDMA_MEM_TO_MEM;
2383d5b3b0aSRuslan Bukin 	sc->req.src_addr = sc->src_phys;
2393d5b3b0aSRuslan Bukin 	sc->req.dst_addr = sc->dst_phys;
2403d5b3b0aSRuslan Bukin 	sc->req.src_width = 4;
2413d5b3b0aSRuslan Bukin 	sc->req.dst_width = 4;
2423d5b3b0aSRuslan Bukin 	sc->req.block_len = sc->len;
2433d5b3b0aSRuslan Bukin 	sc->req.block_num = 1;
2443d5b3b0aSRuslan Bukin 
2453d5b3b0aSRuslan Bukin 	err = xdma_request(sc->xchan, sc->src_phys, sc->dst_phys, sc->len);
24685debf7fSRuslan Bukin 	if (err != 0) {
24785debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't configure virtual channel.\n");
24885debf7fSRuslan Bukin 		return (-1);
24985debf7fSRuslan Bukin 	}
25085debf7fSRuslan Bukin 
25185debf7fSRuslan Bukin 	/* Start operation. */
25285debf7fSRuslan Bukin 	xdma_begin(sc->xchan);
25385debf7fSRuslan Bukin 
25485debf7fSRuslan Bukin 	return (0);
25585debf7fSRuslan Bukin }
25685debf7fSRuslan Bukin 
25785debf7fSRuslan Bukin static int
25885debf7fSRuslan Bukin xdmatest_verify(struct xdmatest_softc *sc)
25985debf7fSRuslan Bukin {
26085debf7fSRuslan Bukin 	int err;
26185debf7fSRuslan Bukin 	int i;
26285debf7fSRuslan Bukin 
26385debf7fSRuslan Bukin 	/* We have memory updated by DMA controller. */
26485debf7fSRuslan Bukin 	bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_POSTREAD);
26585debf7fSRuslan Bukin 	bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_POSTWRITE);
26685debf7fSRuslan Bukin 
26785debf7fSRuslan Bukin 	for (i = 0; i < sc->len; i++) {
26885debf7fSRuslan Bukin 		if (sc->dst[i] != sc->src[i]) {
26985debf7fSRuslan Bukin 			device_printf(sc->dev,
27085debf7fSRuslan Bukin 			    "%s: Test failed: iter %d\n", __func__, i);
27185debf7fSRuslan Bukin 			return (-1);
27285debf7fSRuslan Bukin 		}
27385debf7fSRuslan Bukin 	}
27485debf7fSRuslan Bukin 
27585debf7fSRuslan Bukin 	err = xdma_channel_free(sc->xchan);
27685debf7fSRuslan Bukin 	if (err != 0) {
27785debf7fSRuslan Bukin 		device_printf(sc->dev,
27885debf7fSRuslan Bukin 		    "%s: Test failed: can't deallocate channel.\n", __func__);
27985debf7fSRuslan Bukin 		return (-1);
28085debf7fSRuslan Bukin 	}
28185debf7fSRuslan Bukin 
28285debf7fSRuslan Bukin 	err = xdma_put(sc->xdma);
28385debf7fSRuslan Bukin 	if (err != 0) {
28485debf7fSRuslan Bukin 		device_printf(sc->dev,
28585debf7fSRuslan Bukin 		    "%s: Test failed: can't deallocate xDMA.\n", __func__);
28685debf7fSRuslan Bukin 		return (-1);
28785debf7fSRuslan Bukin 	}
28885debf7fSRuslan Bukin 
28985debf7fSRuslan Bukin 	return (0);
29085debf7fSRuslan Bukin }
29185debf7fSRuslan Bukin 
29285debf7fSRuslan Bukin static void
29385debf7fSRuslan Bukin xdmatest_worker(void *arg)
29485debf7fSRuslan Bukin {
29585debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
29685debf7fSRuslan Bukin 	int timeout;
29785debf7fSRuslan Bukin 	int err;
29885debf7fSRuslan Bukin 
29985debf7fSRuslan Bukin 	sc = arg;
30085debf7fSRuslan Bukin 
30185debf7fSRuslan Bukin 	device_printf(sc->dev, "Worker %d started.\n",
30285debf7fSRuslan Bukin 	    device_get_unit(sc->dev));
30385debf7fSRuslan Bukin 
30485debf7fSRuslan Bukin 	while (1) {
30585debf7fSRuslan Bukin 		sc->done = 0;
30685debf7fSRuslan Bukin 
30785debf7fSRuslan Bukin 		mtx_lock(&sc->mtx);
30885debf7fSRuslan Bukin 
3093d5b3b0aSRuslan Bukin 		if (xdmatest_test(sc) != 0) {
3103d5b3b0aSRuslan Bukin 			mtx_unlock(&sc->mtx);
3113d5b3b0aSRuslan Bukin 			device_printf(sc->dev,
3123d5b3b0aSRuslan Bukin 			    "%s: Test failed.\n", __func__);
3133d5b3b0aSRuslan Bukin 			break;
3143d5b3b0aSRuslan Bukin 		}
31585debf7fSRuslan Bukin 
31685debf7fSRuslan Bukin 		timeout = 100;
31785debf7fSRuslan Bukin 
31885debf7fSRuslan Bukin 		do {
31985debf7fSRuslan Bukin 			mtx_sleep(sc, &sc->mtx, 0, "xdmatest_wait", hz);
32085debf7fSRuslan Bukin 		} while (timeout-- && sc->done == 0);
32185debf7fSRuslan Bukin 
32285debf7fSRuslan Bukin 		if (timeout != 0) {
32385debf7fSRuslan Bukin 			err = xdmatest_verify(sc);
32485debf7fSRuslan Bukin 			if (err == 0) {
32585debf7fSRuslan Bukin 				/* Test succeeded. */
32685debf7fSRuslan Bukin 				mtx_unlock(&sc->mtx);
32785debf7fSRuslan Bukin 				continue;
32885debf7fSRuslan Bukin 			}
32985debf7fSRuslan Bukin 		}
33085debf7fSRuslan Bukin 
33185debf7fSRuslan Bukin 		mtx_unlock(&sc->mtx);
33285debf7fSRuslan Bukin 		device_printf(sc->dev,
33385debf7fSRuslan Bukin 		    "%s: Test failed.\n", __func__);
33485debf7fSRuslan Bukin 		break;
33585debf7fSRuslan Bukin 	}
33685debf7fSRuslan Bukin }
33785debf7fSRuslan Bukin 
33885debf7fSRuslan Bukin static void
33985debf7fSRuslan Bukin xdmatest_delayed_attach(void *arg)
34085debf7fSRuslan Bukin {
34185debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
34285debf7fSRuslan Bukin 
34385debf7fSRuslan Bukin 	sc = arg;
34485debf7fSRuslan Bukin 
34585debf7fSRuslan Bukin 	if (kproc_create(xdmatest_worker, (void *)sc, &sc->newp, 0, 0,
34685debf7fSRuslan Bukin             "xdmatest_worker") != 0) {
34785debf7fSRuslan Bukin 		device_printf(sc->dev,
34885debf7fSRuslan Bukin 		    "%s: Failed to create worker thread.\n", __func__);
34985debf7fSRuslan Bukin 	}
35085debf7fSRuslan Bukin 
35185debf7fSRuslan Bukin 	config_intrhook_disestablish(&sc->config_intrhook);
35285debf7fSRuslan Bukin }
35385debf7fSRuslan Bukin 
35485debf7fSRuslan Bukin static int
35585debf7fSRuslan Bukin xdmatest_probe(device_t dev)
35685debf7fSRuslan Bukin {
35785debf7fSRuslan Bukin 
35885debf7fSRuslan Bukin 	if (!ofw_bus_status_okay(dev))
35985debf7fSRuslan Bukin 		return (ENXIO);
36085debf7fSRuslan Bukin 
36185debf7fSRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "freebsd,xdma-test"))
36285debf7fSRuslan Bukin 		return (ENXIO);
36385debf7fSRuslan Bukin 
36485debf7fSRuslan Bukin 	device_set_desc(dev, "xDMA test driver");
36585debf7fSRuslan Bukin 
36685debf7fSRuslan Bukin 	return (BUS_PROBE_DEFAULT);
36785debf7fSRuslan Bukin }
36885debf7fSRuslan Bukin 
36985debf7fSRuslan Bukin static int
37085debf7fSRuslan Bukin xdmatest_attach(device_t dev)
37185debf7fSRuslan Bukin {
37285debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
37385debf7fSRuslan Bukin 	int err;
37485debf7fSRuslan Bukin 
37585debf7fSRuslan Bukin 	sc = device_get_softc(dev);
37685debf7fSRuslan Bukin 	sc->dev = dev;
37785debf7fSRuslan Bukin 
37885debf7fSRuslan Bukin 	mtx_init(&sc->mtx, device_get_nameunit(dev), "xdmatest", MTX_DEF);
37985debf7fSRuslan Bukin 
38085debf7fSRuslan Bukin 	/* Allocate test memory */
38185debf7fSRuslan Bukin 	err = xdmatest_alloc_test_memory(sc);
38285debf7fSRuslan Bukin 	if (err != 0) {
38385debf7fSRuslan Bukin 		device_printf(sc->dev, "Can't allocate test memory.\n");
38485debf7fSRuslan Bukin 		return (-1);
38585debf7fSRuslan Bukin 	}
38685debf7fSRuslan Bukin 
38785debf7fSRuslan Bukin 	/* We'll run test later, but before / mount. */
38885debf7fSRuslan Bukin 	sc->config_intrhook.ich_func = xdmatest_delayed_attach;
38985debf7fSRuslan Bukin 	sc->config_intrhook.ich_arg = sc;
39085debf7fSRuslan Bukin 	if (config_intrhook_establish(&sc->config_intrhook) != 0)
39185debf7fSRuslan Bukin 		device_printf(dev, "config_intrhook_establish failed\n");
39285debf7fSRuslan Bukin 
39385debf7fSRuslan Bukin 	return (0);
39485debf7fSRuslan Bukin }
39585debf7fSRuslan Bukin 
39685debf7fSRuslan Bukin static int
39785debf7fSRuslan Bukin xdmatest_detach(device_t dev)
39885debf7fSRuslan Bukin {
39985debf7fSRuslan Bukin 	struct xdmatest_softc *sc;
40085debf7fSRuslan Bukin 
40185debf7fSRuslan Bukin 	sc = device_get_softc(dev);
40285debf7fSRuslan Bukin 
40385debf7fSRuslan Bukin 	bus_dmamap_unload(sc->src_dma_tag, sc->src_dma_map);
40485debf7fSRuslan Bukin 	bus_dmamem_free(sc->src_dma_tag, sc->src, sc->src_dma_map);
40585debf7fSRuslan Bukin 	bus_dma_tag_destroy(sc->src_dma_tag);
40685debf7fSRuslan Bukin 
40785debf7fSRuslan Bukin 	bus_dmamap_unload(sc->dst_dma_tag, sc->dst_dma_map);
40885debf7fSRuslan Bukin 	bus_dmamem_free(sc->dst_dma_tag, sc->dst, sc->dst_dma_map);
40985debf7fSRuslan Bukin 	bus_dma_tag_destroy(sc->dst_dma_tag);
41085debf7fSRuslan Bukin 
41185debf7fSRuslan Bukin 	return (0);
41285debf7fSRuslan Bukin }
41385debf7fSRuslan Bukin 
41485debf7fSRuslan Bukin static device_method_t xdmatest_methods[] = {
41585debf7fSRuslan Bukin 	/* Device interface */
41685debf7fSRuslan Bukin 	DEVMETHOD(device_probe,			xdmatest_probe),
41785debf7fSRuslan Bukin 	DEVMETHOD(device_attach,		xdmatest_attach),
41885debf7fSRuslan Bukin 	DEVMETHOD(device_detach,		xdmatest_detach),
41985debf7fSRuslan Bukin 
42085debf7fSRuslan Bukin 	DEVMETHOD_END
42185debf7fSRuslan Bukin };
42285debf7fSRuslan Bukin 
42385debf7fSRuslan Bukin static driver_t xdmatest_driver = {
42485debf7fSRuslan Bukin 	"xdmatest",
42585debf7fSRuslan Bukin 	xdmatest_methods,
42685debf7fSRuslan Bukin 	sizeof(struct xdmatest_softc),
42785debf7fSRuslan Bukin };
42885debf7fSRuslan Bukin 
42985debf7fSRuslan Bukin static devclass_t xdmatest_devclass;
43085debf7fSRuslan Bukin 
43185debf7fSRuslan Bukin DRIVER_MODULE(xdmatest, simplebus, xdmatest_driver, xdmatest_devclass, 0, 0);
432