The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/xdma/xdma_fdt_test.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
    3  * All rights reserved.
    4  *
    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.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   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.
   17  *
   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
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /* xDMA memcpy test driver. */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/conf.h>
   39 #include <sys/bus.h>
   40 #include <sys/kernel.h>
   41 #include <sys/kthread.h>
   42 #include <sys/module.h>
   43 #include <sys/lock.h>
   44 #include <sys/mutex.h>
   45 #include <sys/resource.h>
   46 #include <sys/rman.h>
   47 
   48 #include <machine/bus.h>
   49 
   50 #include <dev/xdma/xdma.h>
   51 
   52 #include <dev/fdt/fdt_common.h>
   53 #include <dev/ofw/ofw_bus.h>
   54 #include <dev/ofw/ofw_bus_subr.h>
   55 
   56 /*
   57  * To use this test add a compatible node to your dts, e.g.
   58  *
   59  *      xdma_test {
   60  *              compatible = "freebsd,xdma-test";
   61  *
   62  *              dmas = <&dma 0 0 0xffffffff>;
   63  *              dma-names = "test";
   64  *      };
   65  */
   66 
   67 struct xdmatest_softc {
   68         device_t                dev;
   69         xdma_controller_t       *xdma;
   70         xdma_channel_t          *xchan;
   71         void                    *ih;
   72         struct intr_config_hook config_intrhook;
   73         char                    *src;
   74         char                    *dst;
   75         uint32_t                len;
   76         uintptr_t               src_phys;
   77         uintptr_t               dst_phys;
   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;
   82         struct mtx              mtx;
   83         int                     done;
   84         struct proc             *newp;
   85         struct xdma_request     req;
   86 };
   87 
   88 static int xdmatest_probe(device_t dev);
   89 static int xdmatest_attach(device_t dev);
   90 static int xdmatest_detach(device_t dev);
   91 
   92 static int
   93 xdmatest_intr(void *arg)
   94 {
   95         struct xdmatest_softc *sc;
   96 
   97         sc = arg;
   98 
   99         sc->done = 1;
  100 
  101         mtx_lock(&sc->mtx);
  102         wakeup(sc);
  103         mtx_unlock(&sc->mtx);
  104 
  105         return (0);
  106 }
  107 
  108 static void
  109 xdmatest_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
  110 {
  111         bus_addr_t *addr;
  112 
  113         if (err)
  114                 return;
  115 
  116         addr = (bus_addr_t*)arg;
  117         *addr = segs[0].ds_addr;
  118 }
  119 
  120 static int
  121 xdmatest_alloc_test_memory(struct xdmatest_softc *sc)
  122 {
  123         int err;
  124 
  125         sc->len = (0x1000000 - 8); /* 16mb */
  126         sc->len = 8;
  127 
  128         /* Source memory. */
  129 
  130         err = bus_dma_tag_create(
  131             bus_get_dma_tag(sc->dev),
  132             1024, 0,                    /* alignment, boundary */
  133             BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
  134             BUS_SPACE_MAXADDR,          /* highaddr */
  135             NULL, NULL,                 /* filter, filterarg */
  136             sc->len, 1,                 /* maxsize, nsegments*/
  137             sc->len, 0,                 /* maxsegsize, flags */
  138             NULL, NULL,                 /* lockfunc, lockarg */
  139             &sc->src_dma_tag);
  140         if (err) {
  141                 device_printf(sc->dev,
  142                     "%s: Can't create bus_dma tag.\n", __func__);
  143                 return (-1);
  144         }
  145 
  146         err = bus_dmamem_alloc(sc->src_dma_tag, (void **)&sc->src,
  147             BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->src_dma_map);
  148         if (err) {
  149                 device_printf(sc->dev,
  150                     "%s: Can't allocate memory.\n", __func__);
  151                 return (-1);
  152         }
  153 
  154         err = bus_dmamap_load(sc->src_dma_tag, sc->src_dma_map, sc->src,
  155             sc->len, xdmatest_dmamap_cb, &sc->src_phys, BUS_DMA_WAITOK);
  156         if (err) {
  157                 device_printf(sc->dev,
  158                     "%s: Can't load DMA map.\n", __func__);
  159                 return (-1);
  160         }
  161 
  162         /* Destination memory. */
  163 
  164         err = bus_dma_tag_create(
  165             bus_get_dma_tag(sc->dev),
  166             1024, 0,                    /* alignment, boundary */
  167             BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
  168             BUS_SPACE_MAXADDR,          /* highaddr */
  169             NULL, NULL,                 /* filter, filterarg */
  170             sc->len, 1,                 /* maxsize, nsegments*/
  171             sc->len, 0,                 /* maxsegsize, flags */
  172             NULL, NULL,                 /* lockfunc, lockarg */
  173             &sc->dst_dma_tag);
  174         if (err) {
  175                 device_printf(sc->dev,
  176                     "%s: Can't create bus_dma tag.\n", __func__);
  177                 return (-1);
  178         }
  179 
  180         err = bus_dmamem_alloc(sc->dst_dma_tag, (void **)&sc->dst,
  181             BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->dst_dma_map);
  182         if (err) {
  183                 device_printf(sc->dev,
  184                     "%s: Can't allocate memory.\n", __func__);
  185                 return (-1);
  186         }
  187 
  188         err = bus_dmamap_load(sc->dst_dma_tag, sc->dst_dma_map, sc->dst,
  189             sc->len, xdmatest_dmamap_cb, &sc->dst_phys, BUS_DMA_WAITOK);
  190         if (err) {
  191                 device_printf(sc->dev,
  192                     "%s: Can't load DMA map.\n", __func__);
  193                 return (-1);
  194         }
  195 
  196         return (0);
  197 }
  198 
  199 static int
  200 xdmatest_test(struct xdmatest_softc *sc)
  201 {
  202         int err;
  203         int i;
  204 
  205         /* Get xDMA controller. */
  206         sc->xdma = xdma_ofw_get(sc->dev, "test");
  207         if (sc->xdma == NULL) {
  208                 device_printf(sc->dev, "Can't find xDMA controller.\n");
  209                 return (-1);
  210         }
  211 
  212         /* Alloc xDMA virtual channel. */
  213         sc->xchan = xdma_channel_alloc(sc->xdma);
  214         if (sc->xchan == NULL) {
  215                 device_printf(sc->dev, "Can't alloc virtual DMA channel.\n");
  216                 return (-1);
  217         }
  218 
  219         /* Setup callback. */
  220         err = xdma_setup_intr(sc->xchan, 0, xdmatest_intr, sc, &sc->ih);
  221         if (err) {
  222                 device_printf(sc->dev, "Can't setup xDMA interrupt handler.\n");
  223                 return (-1);
  224         }
  225 
  226         /* We are going to fill memory. */
  227         bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_PREWRITE);
  228         bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_PREWRITE);
  229 
  230         /* Fill memory. */
  231         for (i = 0; i < sc->len; i++) {
  232                 sc->src[i] = (i & 0xff);
  233                 sc->dst[i] = 0;
  234         }
  235 
  236         sc->req.type = XR_TYPE_PHYS_ADDR;
  237         sc->req.direction = XDMA_MEM_TO_MEM;
  238         sc->req.src_addr = sc->src_phys;
  239         sc->req.dst_addr = sc->dst_phys;
  240         sc->req.src_width = 4;
  241         sc->req.dst_width = 4;
  242         sc->req.block_len = sc->len;
  243         sc->req.block_num = 1;
  244 
  245         err = xdma_request(sc->xchan, sc->src_phys, sc->dst_phys, sc->len);
  246         if (err != 0) {
  247                 device_printf(sc->dev, "Can't configure virtual channel.\n");
  248                 return (-1);
  249         }
  250 
  251         /* Start operation. */
  252         xdma_begin(sc->xchan);
  253 
  254         return (0);
  255 }
  256 
  257 static int
  258 xdmatest_verify(struct xdmatest_softc *sc)
  259 {
  260         int err;
  261         int i;
  262 
  263         /* We have memory updated by DMA controller. */
  264         bus_dmamap_sync(sc->src_dma_tag, sc->src_dma_map, BUS_DMASYNC_POSTREAD);
  265         bus_dmamap_sync(sc->dst_dma_tag, sc->dst_dma_map, BUS_DMASYNC_POSTWRITE);
  266 
  267         for (i = 0; i < sc->len; i++) {
  268                 if (sc->dst[i] != sc->src[i]) {
  269                         device_printf(sc->dev,
  270                             "%s: Test failed: iter %d\n", __func__, i);
  271                         return (-1);
  272                 }
  273         }
  274 
  275         err = xdma_channel_free(sc->xchan);
  276         if (err != 0) {
  277                 device_printf(sc->dev,
  278                     "%s: Test failed: can't deallocate channel.\n", __func__);
  279                 return (-1);
  280         }
  281 
  282         err = xdma_put(sc->xdma);
  283         if (err != 0) {
  284                 device_printf(sc->dev,
  285                     "%s: Test failed: can't deallocate xDMA.\n", __func__);
  286                 return (-1);
  287         }
  288 
  289         return (0);
  290 }
  291 
  292 static void
  293 xdmatest_worker(void *arg)
  294 {
  295         struct xdmatest_softc *sc;
  296         int timeout;
  297         int err;
  298 
  299         sc = arg;
  300 
  301         device_printf(sc->dev, "Worker %d started.\n",
  302             device_get_unit(sc->dev));
  303 
  304         while (1) {
  305                 sc->done = 0;
  306 
  307                 mtx_lock(&sc->mtx);
  308 
  309                 if (xdmatest_test(sc) != 0) {
  310                         mtx_unlock(&sc->mtx);
  311                         device_printf(sc->dev,
  312                             "%s: Test failed.\n", __func__);
  313                         break;
  314                 }
  315 
  316                 timeout = 100;
  317 
  318                 do {
  319                         mtx_sleep(sc, &sc->mtx, 0, "xdmatest_wait", hz);
  320                 } while (timeout-- && sc->done == 0);
  321 
  322                 if (timeout != 0) {
  323                         err = xdmatest_verify(sc);
  324                         if (err == 0) {
  325                                 /* Test succeeded. */
  326                                 mtx_unlock(&sc->mtx);
  327                                 continue;
  328                         }
  329                 }
  330 
  331                 mtx_unlock(&sc->mtx);
  332                 device_printf(sc->dev,
  333                     "%s: Test failed.\n", __func__);
  334                 break;
  335         }
  336 }
  337 
  338 static void
  339 xdmatest_delayed_attach(void *arg)
  340 {
  341         struct xdmatest_softc *sc;
  342 
  343         sc = arg;
  344 
  345         if (kproc_create(xdmatest_worker, (void *)sc, &sc->newp, 0, 0,
  346             "xdmatest_worker") != 0) {
  347                 device_printf(sc->dev,
  348                     "%s: Failed to create worker thread.\n", __func__);
  349         }
  350 
  351         config_intrhook_disestablish(&sc->config_intrhook);
  352 }
  353 
  354 static int
  355 xdmatest_probe(device_t dev)
  356 {
  357 
  358         if (!ofw_bus_status_okay(dev))
  359                 return (ENXIO);
  360 
  361         if (!ofw_bus_is_compatible(dev, "freebsd,xdma-test"))
  362                 return (ENXIO);
  363 
  364         device_set_desc(dev, "xDMA test driver");
  365 
  366         return (BUS_PROBE_DEFAULT);
  367 }
  368 
  369 static int
  370 xdmatest_attach(device_t dev)
  371 {
  372         struct xdmatest_softc *sc;
  373         int err;
  374 
  375         sc = device_get_softc(dev);
  376         sc->dev = dev;
  377 
  378         mtx_init(&sc->mtx, device_get_nameunit(dev), "xdmatest", MTX_DEF);
  379 
  380         /* Allocate test memory */
  381         err = xdmatest_alloc_test_memory(sc);
  382         if (err != 0) {
  383                 device_printf(sc->dev, "Can't allocate test memory.\n");
  384                 return (-1);
  385         }
  386 
  387         /* We'll run test later, but before / mount. */
  388         sc->config_intrhook.ich_func = xdmatest_delayed_attach;
  389         sc->config_intrhook.ich_arg = sc;
  390         if (config_intrhook_establish(&sc->config_intrhook) != 0)
  391                 device_printf(dev, "config_intrhook_establish failed\n");
  392 
  393         return (0);
  394 }
  395 
  396 static int
  397 xdmatest_detach(device_t dev)
  398 {
  399         struct xdmatest_softc *sc;
  400 
  401         sc = device_get_softc(dev);
  402 
  403         bus_dmamap_unload(sc->src_dma_tag, sc->src_dma_map);
  404         bus_dmamem_free(sc->src_dma_tag, sc->src, sc->src_dma_map);
  405         bus_dma_tag_destroy(sc->src_dma_tag);
  406 
  407         bus_dmamap_unload(sc->dst_dma_tag, sc->dst_dma_map);
  408         bus_dmamem_free(sc->dst_dma_tag, sc->dst, sc->dst_dma_map);
  409         bus_dma_tag_destroy(sc->dst_dma_tag);
  410 
  411         return (0);
  412 }
  413 
  414 static device_method_t xdmatest_methods[] = {
  415         /* Device interface */
  416         DEVMETHOD(device_probe,                 xdmatest_probe),
  417         DEVMETHOD(device_attach,                xdmatest_attach),
  418         DEVMETHOD(device_detach,                xdmatest_detach),
  419 
  420         DEVMETHOD_END
  421 };
  422 
  423 static driver_t xdmatest_driver = {
  424         "xdmatest",
  425         xdmatest_methods,
  426         sizeof(struct xdmatest_softc),
  427 };
  428 
  429 DRIVER_MODULE(xdmatest, simplebus, xdmatest_driver, 0, 0);

Cache object: 797f2ccc584594764dc179b8c44b6dc2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.