]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/proto/proto_busdma.c
DMA support part 1: DMA tag create & destroy
[FreeBSD/FreeBSD.git] / sys / dev / proto / proto_busdma.c
1 /*-
2  * Copyright (c) 2015 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <machine/bus.h>
32 #include <machine/bus_dma.h>
33 #include <machine/resource.h>
34 #include <sys/bus.h>
35 #include <sys/conf.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/queue.h>
40 #include <sys/rman.h>
41 #include <sys/sbuf.h>
42
43 #include <dev/proto/proto.h>
44 #include <dev/proto/proto_dev.h>
45 #include <dev/proto/proto_busdma.h>
46
47 MALLOC_DEFINE(M_PROTO_BUSDMA, "proto_busdma", "DMA management data");
48
49 static int
50 proto_busdma_tag_create(struct proto_ioc_busdma *ioc,
51     struct proto_tag **tag_io, bus_dma_tag_t *busdma_tag_io)
52 {
53         struct proto_tag *tag;
54         int error;
55
56         error = bus_dma_tag_create(*busdma_tag_io, ioc->u.tag.align,
57             ioc->u.tag.bndry, ioc->u.tag.maxaddr, BUS_SPACE_MAXADDR,
58             NULL, NULL, ioc->u.tag.maxsz, ioc->u.tag.nsegs,
59             ioc->u.tag.maxsegsz, ioc->u.tag.flags, NULL, NULL,
60             busdma_tag_io);
61         if (error)
62                 return (error);
63
64         tag = malloc(sizeof(*tag), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
65         tag->parent = *tag_io;
66         tag->busdma_tag = *busdma_tag_io;
67         *tag_io = tag;
68         return (0);
69 }
70
71 static void
72 proto_busdma_tag_destroy(struct proto_tag *tag)
73 {
74
75         bus_dma_tag_destroy(tag->busdma_tag);
76         free(tag, M_PROTO_BUSDMA);
77 }
78
79 static struct proto_tag *
80 proto_busdma_tag_lookup(struct proto_busdma *busdma, u_long key)
81 {
82         struct proto_tag *tag;
83
84         LIST_FOREACH(tag, &busdma->tags, link) {
85                 if ((void *)tag == (void *)key)
86                         return (tag);
87         }
88         return (NULL);
89 }
90
91 struct proto_busdma *
92 proto_busdma_attach(struct proto_softc *sc)
93 {
94         struct proto_busdma *busdma;
95
96         busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
97         return (busdma);
98 }
99
100 int
101 proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
102 {
103
104         proto_busdma_cleanup(sc, busdma);
105         free(busdma, M_PROTO_BUSDMA);
106         return (0);
107 }
108
109 int
110 proto_busdma_cleanup(struct proto_softc *sc, struct proto_busdma *busdma)
111 {
112         struct proto_tag *tag, *tag1;
113
114         LIST_FOREACH_SAFE(tag, &busdma->tags, link, tag1) {
115                 LIST_REMOVE(tag, link);
116                 proto_busdma_tag_destroy(tag);
117         }
118         return (0);
119 }
120
121 int
122 proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
123     struct proto_ioc_busdma *ioc)
124 {
125         struct proto_tag *tag;
126         bus_dma_tag_t busdma_tag;
127         int error;
128
129         error = 0;
130         switch (ioc->request) {
131         case PROTO_IOC_BUSDMA_TAG_CREATE:
132                 busdma_tag = bus_get_dma_tag(sc->sc_dev);
133                 tag = NULL;
134                 error = proto_busdma_tag_create(ioc, &tag, &busdma_tag);
135                 if (error)
136                         break;
137                 LIST_INSERT_HEAD(&busdma->tags, tag, link);
138                 ioc->key = (uintptr_t)(void *)tag;
139                 break;
140         case PROTO_IOC_BUSDMA_TAG_DERIVE:
141                 tag = proto_busdma_tag_lookup(busdma, ioc->key);
142                 if (tag == NULL) {
143                         error = EINVAL;
144                         break;
145                 }
146                 busdma_tag = tag->busdma_tag;
147                 error = proto_busdma_tag_create(ioc, &tag, &busdma_tag);
148                 if (error)
149                         break;
150                 LIST_INSERT_HEAD(&busdma->tags, tag, link);
151                 ioc->key = (uintptr_t)(void *)tag;
152                 break;
153         case PROTO_IOC_BUSDMA_TAG_DESTROY:
154                 tag = proto_busdma_tag_lookup(busdma, ioc->key);
155                 if (tag == NULL) {
156                         error = EINVAL;
157                         break;
158                 }
159                 LIST_REMOVE(tag, link);
160                 proto_busdma_tag_destroy(tag);
161                 break;
162         default:
163                 error = EINVAL;
164                 break;
165         }
166         return (error);
167 }