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