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