]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/xdma/xdma_fdt_test.c
MFV r330591: 8984 fix for 6764 breaks ACL inheritance
[FreeBSD/FreeBSD.git] / sys / dev / xdma / xdma_fdt_test.c
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 };
86
87 static int xdmatest_probe(device_t dev);
88 static int xdmatest_attach(device_t dev);
89 static int xdmatest_detach(device_t dev);
90
91 static int
92 xdmatest_intr(void *arg)
93 {
94         struct xdmatest_softc *sc;
95
96         sc = arg;
97
98         sc->done = 1;
99
100         mtx_lock(&sc->mtx);
101         wakeup(sc);
102         mtx_unlock(&sc->mtx);
103
104         return (0);
105 }
106
107 static void
108 xdmatest_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
109 {
110         bus_addr_t *addr;
111
112         if (err)
113                 return;
114
115         addr = (bus_addr_t*)arg;
116         *addr = segs[0].ds_addr;
117 }
118
119 static int
120 xdmatest_alloc_test_memory(struct xdmatest_softc *sc)
121 {
122         int err;
123
124         sc->len = (0x1000000 - 8); /* 16mb */
125         sc->len = 8;
126
127         /* Source memory. */
128
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 */
138             &sc->src_dma_tag);
139         if (err) {
140                 device_printf(sc->dev,
141                     "%s: Can't create bus_dma tag.\n", __func__);
142                 return (-1);
143         }
144
145         err = bus_dmamem_alloc(sc->src_dma_tag, (void **)&sc->src,
146             BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->src_dma_map);
147         if (err) {
148                 device_printf(sc->dev,
149                     "%s: Can't allocate memory.\n", __func__);
150                 return (-1);
151         }
152
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);
155         if (err) {
156                 device_printf(sc->dev,
157                     "%s: Can't load DMA map.\n", __func__);
158                 return (-1);
159         }
160
161         /* Destination memory. */
162
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 */
172             &sc->dst_dma_tag);
173         if (err) {
174                 device_printf(sc->dev,
175                     "%s: Can't create bus_dma tag.\n", __func__);
176                 return (-1);
177         }
178
179         err = bus_dmamem_alloc(sc->dst_dma_tag, (void **)&sc->dst,
180             BUS_DMA_WAITOK | BUS_DMA_COHERENT, &sc->dst_dma_map);
181         if (err) {
182                 device_printf(sc->dev,
183                     "%s: Can't allocate memory.\n", __func__);
184                 return (-1);
185         }
186
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);
189         if (err) {
190                 device_printf(sc->dev,
191                     "%s: Can't load DMA map.\n", __func__);
192                 return (-1);
193         }
194
195         return (0);
196 }
197
198 static int
199 xdmatest_test(struct xdmatest_softc *sc)
200 {
201         int err;
202         int i;
203
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");
208                 return (-1);
209         }
210
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");
215                 return (-1);
216         }
217
218         /* Setup callback. */
219         err = xdma_setup_intr(sc->xchan, xdmatest_intr, sc, &sc->ih);
220         if (err) {
221                 device_printf(sc->dev, "Can't setup xDMA interrupt handler.\n");
222                 return (-1);
223         }
224
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);
228
229         /* Fill memory. */
230         for (i = 0; i < sc->len; i++) {
231                 sc->src[i] = (i & 0xff);
232                 sc->dst[i] = 0;
233         }
234
235         /* Configure channel for memcpy transfer. */
236         err = xdma_prep_memcpy(sc->xchan, sc->src_phys, sc->dst_phys, sc->len);
237         if (err != 0) {
238                 device_printf(sc->dev, "Can't configure virtual channel.\n");
239                 return (-1);
240         }
241
242         /* Start operation. */
243         xdma_begin(sc->xchan);
244
245         return (0);
246 }
247
248 static int
249 xdmatest_verify(struct xdmatest_softc *sc)
250 {
251         int err;
252         int i;
253
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);
257
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);
262                         return (-1);
263                 }
264         }
265
266         err = xdma_channel_free(sc->xchan);
267         if (err != 0) {
268                 device_printf(sc->dev,
269                     "%s: Test failed: can't deallocate channel.\n", __func__);
270                 return (-1);
271         }
272
273         err = xdma_put(sc->xdma);
274         if (err != 0) {
275                 device_printf(sc->dev,
276                     "%s: Test failed: can't deallocate xDMA.\n", __func__);
277                 return (-1);
278         }
279
280         return (0);
281 }
282
283 static void
284 xdmatest_worker(void *arg)
285 {
286         struct xdmatest_softc *sc;
287         int timeout;
288         int err;
289
290         sc = arg;
291
292         device_printf(sc->dev, "Worker %d started.\n",
293             device_get_unit(sc->dev));
294
295         while (1) {
296                 sc->done = 0;
297
298                 mtx_lock(&sc->mtx);
299
300                 xdmatest_test(sc);
301
302                 timeout = 100;
303
304                 do {
305                         mtx_sleep(sc, &sc->mtx, 0, "xdmatest_wait", hz);
306                 } while (timeout-- && sc->done == 0);
307
308                 if (timeout != 0) {
309                         err = xdmatest_verify(sc);
310                         if (err == 0) {
311                                 /* Test succeeded. */
312                                 mtx_unlock(&sc->mtx);
313                                 continue;
314                         }
315                 }
316
317                 mtx_unlock(&sc->mtx);
318                 device_printf(sc->dev,
319                     "%s: Test failed.\n", __func__);
320                 break;
321         }
322 }
323
324 static void
325 xdmatest_delayed_attach(void *arg)
326 {
327         struct xdmatest_softc *sc;
328
329         sc = arg;
330
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__);
335         }
336
337         config_intrhook_disestablish(&sc->config_intrhook);
338 }
339
340 static int
341 xdmatest_probe(device_t dev)
342 {
343
344         if (!ofw_bus_status_okay(dev))
345                 return (ENXIO);
346
347         if (!ofw_bus_is_compatible(dev, "freebsd,xdma-test"))
348                 return (ENXIO);
349
350         device_set_desc(dev, "xDMA test driver");
351
352         return (BUS_PROBE_DEFAULT);
353 }
354
355 static int
356 xdmatest_attach(device_t dev)
357 {
358         struct xdmatest_softc *sc;
359         int err;
360
361         sc = device_get_softc(dev);
362         sc->dev = dev;
363
364         mtx_init(&sc->mtx, device_get_nameunit(dev), "xdmatest", MTX_DEF);
365
366         /* Allocate test memory */
367         err = xdmatest_alloc_test_memory(sc);
368         if (err != 0) {
369                 device_printf(sc->dev, "Can't allocate test memory.\n");
370                 return (-1);
371         }
372
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");
378
379         return (0);
380 }
381
382 static int
383 xdmatest_detach(device_t dev)
384 {
385         struct xdmatest_softc *sc;
386
387         sc = device_get_softc(dev);
388
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);
392
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);
396
397         return (0);
398 }
399
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),
405
406         DEVMETHOD_END
407 };
408
409 static driver_t xdmatest_driver = {
410         "xdmatest",
411         xdmatest_methods,
412         sizeof(struct xdmatest_softc),
413 };
414
415 static devclass_t xdmatest_devclass;
416
417 DRIVER_MODULE(xdmatest, simplebus, xdmatest_driver, xdmatest_devclass, 0, 0);