2 * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 /* xDMA memcpy test driver. */
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/kthread.h>
42 #include <sys/module.h>
44 #include <sys/mutex.h>
45 #include <sys/resource.h>
48 #include <machine/bus.h>
50 #include <dev/xdma/xdma.h>
52 #include <dev/fdt/fdt_common.h>
53 #include <dev/ofw/ofw_bus.h>
54 #include <dev/ofw/ofw_bus_subr.h>
57 * To use this test add a compatible node to your dts, e.g.
60 * compatible = "freebsd,xdma-test";
62 * dmas = <&dma 0 0 0xffffffff>;
67 struct xdmatest_softc {
69 xdma_controller_t *xdma;
70 xdma_channel_t *xchan;
72 struct intr_config_hook config_intrhook;
78 bus_dma_tag_t src_dma_tag;
79 bus_dmamap_t src_dma_map;
80 bus_dma_tag_t dst_dma_tag;
81 bus_dmamap_t dst_dma_map;
87 static int xdmatest_probe(device_t dev);
88 static int xdmatest_attach(device_t dev);
89 static int xdmatest_detach(device_t dev);
92 xdmatest_intr(void *arg)
94 struct xdmatest_softc *sc;
102 mtx_unlock(&sc->mtx);
108 xdmatest_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
115 addr = (bus_addr_t*)arg;
116 *addr = segs[0].ds_addr;
120 xdmatest_alloc_test_memory(struct xdmatest_softc *sc)
124 sc->len = (0x1000000 - 8); /* 16mb */
129 err = bus_dma_tag_create(
130 bus_get_dma_tag(sc->dev),
131 1024, 0, /* alignment, boundary */
132 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
133 BUS_SPACE_MAXADDR, /* highaddr */
134 NULL, NULL, /* filter, filterarg */
135 sc->len, 1, /* maxsize, nsegments*/
136 sc->len, 0, /* maxsegsize, flags */
137 NULL, NULL, /* lockfunc, lockarg */
140 device_printf(sc->dev,
141 "%s: Can't create bus_dma tag.\n", __func__);
145 err = bus_dmamem_alloc(sc->src_dma_tag, (void **)&sc->src,
146 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->src_dma_map);
148 device_printf(sc->dev,
149 "%s: Can't allocate memory.\n", __func__);
153 err = bus_dmamap_load(sc->src_dma_tag, sc->src_dma_map, sc->src,
154 sc->len, xdmatest_dmamap_cb, &sc->src_phys, BUS_DMA_WAITOK);
156 device_printf(sc->dev,
157 "%s: Can't load DMA map.\n", __func__);
161 /* Destination memory. */
163 err = bus_dma_tag_create(
164 bus_get_dma_tag(sc->dev),
165 1024, 0, /* alignment, boundary */
166 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
167 BUS_SPACE_MAXADDR, /* highaddr */
168 NULL, NULL, /* filter, filterarg */
169 sc->len, 1, /* maxsize, nsegments*/
170 sc->len, 0, /* maxsegsize, flags */
171 NULL, NULL, /* lockfunc, lockarg */
174 device_printf(sc->dev,
175 "%s: Can't create bus_dma tag.\n", __func__);
179 err = bus_dmamem_alloc(sc->dst_dma_tag, (void **)&sc->dst,
180 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->dst_dma_map);
182 device_printf(sc->dev,
183 "%s: Can't allocate memory.\n", __func__);
187 err = bus_dmamap_load(sc->dst_dma_tag, sc->dst_dma_map, sc->dst,
188 sc->len, xdmatest_dmamap_cb, &sc->dst_phys, BUS_DMA_WAITOK);
190 device_printf(sc->dev,
191 "%s: Can't load DMA map.\n", __func__);
199 xdmatest_test(struct xdmatest_softc *sc)
204 /* Get xDMA controller. */
205 sc->xdma = xdma_ofw_get(sc->dev, "test");
206 if (sc->xdma == NULL) {
207 device_printf(sc->dev, "Can't find xDMA controller.\n");
211 /* Alloc xDMA virtual channel. */
212 sc->xchan = xdma_channel_alloc(sc->xdma);
213 if (sc->xchan == NULL) {
214 device_printf(sc->dev, "Can't alloc virtual DMA channel.\n");
218 /* Setup callback. */
219 err = xdma_setup_intr(sc->xchan, xdmatest_intr, sc, &sc->ih);
221 device_printf(sc->dev, "Can't setup xDMA interrupt handler.\n");
225 /* We are going to fill memory. */
226 bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_PREWRITE);
227 bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_PREWRITE);
230 for (i = 0; i < sc->len; i++) {
231 sc->src[i] = (i & 0xff);
235 /* Configure channel for memcpy transfer. */
236 err = xdma_prep_memcpy(sc->xchan, sc->src_phys, sc->dst_phys, sc->len);
238 device_printf(sc->dev, "Can't configure virtual channel.\n");
242 /* Start operation. */
243 xdma_begin(sc->xchan);
249 xdmatest_verify(struct xdmatest_softc *sc)
254 /* We have memory updated by DMA controller. */
255 bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_POSTREAD);
256 bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_POSTWRITE);
258 for (i = 0; i < sc->len; i++) {
259 if (sc->dst[i] != sc->src[i]) {
260 device_printf(sc->dev,
261 "%s: Test failed: iter %d\n", __func__, i);
266 err = xdma_channel_free(sc->xchan);
268 device_printf(sc->dev,
269 "%s: Test failed: can't deallocate channel.\n", __func__);
273 err = xdma_put(sc->xdma);
275 device_printf(sc->dev,
276 "%s: Test failed: can't deallocate xDMA.\n", __func__);
284 xdmatest_worker(void *arg)
286 struct xdmatest_softc *sc;
292 device_printf(sc->dev, "Worker %d started.\n",
293 device_get_unit(sc->dev));
305 mtx_sleep(sc, &sc->mtx, 0, "xdmatest_wait", hz);
306 } while (timeout-- && sc->done == 0);
309 err = xdmatest_verify(sc);
311 /* Test succeeded. */
312 mtx_unlock(&sc->mtx);
317 mtx_unlock(&sc->mtx);
318 device_printf(sc->dev,
319 "%s: Test failed.\n", __func__);
325 xdmatest_delayed_attach(void *arg)
327 struct xdmatest_softc *sc;
331 if (kproc_create(xdmatest_worker, (void *)sc, &sc->newp, 0, 0,
332 "xdmatest_worker") != 0) {
333 device_printf(sc->dev,
334 "%s: Failed to create worker thread.\n", __func__);
337 config_intrhook_disestablish(&sc->config_intrhook);
341 xdmatest_probe(device_t dev)
344 if (!ofw_bus_status_okay(dev))
347 if (!ofw_bus_is_compatible(dev, "freebsd,xdma-test"))
350 device_set_desc(dev, "xDMA test driver");
352 return (BUS_PROBE_DEFAULT);
356 xdmatest_attach(device_t dev)
358 struct xdmatest_softc *sc;
361 sc = device_get_softc(dev);
364 mtx_init(&sc->mtx, device_get_nameunit(dev), "xdmatest", MTX_DEF);
366 /* Allocate test memory */
367 err = xdmatest_alloc_test_memory(sc);
369 device_printf(sc->dev, "Can't allocate test memory.\n");
373 /* We'll run test later, but before / mount. */
374 sc->config_intrhook.ich_func = xdmatest_delayed_attach;
375 sc->config_intrhook.ich_arg = sc;
376 if (config_intrhook_establish(&sc->config_intrhook) != 0)
377 device_printf(dev, "config_intrhook_establish failed\n");
383 xdmatest_detach(device_t dev)
385 struct xdmatest_softc *sc;
387 sc = device_get_softc(dev);
389 bus_dmamap_unload(sc->src_dma_tag, sc->src_dma_map);
390 bus_dmamem_free(sc->src_dma_tag, sc->src, sc->src_dma_map);
391 bus_dma_tag_destroy(sc->src_dma_tag);
393 bus_dmamap_unload(sc->dst_dma_tag, sc->dst_dma_map);
394 bus_dmamem_free(sc->dst_dma_tag, sc->dst, sc->dst_dma_map);
395 bus_dma_tag_destroy(sc->dst_dma_tag);
400 static device_method_t xdmatest_methods[] = {
401 /* Device interface */
402 DEVMETHOD(device_probe, xdmatest_probe),
403 DEVMETHOD(device_attach, xdmatest_attach),
404 DEVMETHOD(device_detach, xdmatest_detach),
409 static driver_t xdmatest_driver = {
412 sizeof(struct xdmatest_softc),
415 static devclass_t xdmatest_devclass;
417 DRIVER_MODULE(xdmatest, simplebus, xdmatest_driver, xdmatest_devclass, 0, 0);