2 * Copyright (c) 2015 Marcel Moolenaar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/ioctl.h>
42 #include "../../sys/dev/proto/proto_dev.h"
47 #define OBJ_TYPE_NONE 0
48 #define OBJ_TYPE_TAG 1
50 #define OBJ_TYPE_SEG 3
59 unsigned long maxaddr;
61 unsigned long maxsegsz;
63 unsigned long datarate;
68 #define BUSDMA_MD_BUS 0
69 #define BUSDMA_MD_PHYS 1
70 #define BUSDMA_MD_VIRT 2
74 unsigned long address;
80 static struct obj **oidtbl = NULL;
86 struct obj **newtbl, *obj;
89 obj = calloc(1, sizeof(struct obj));
92 for (oid = 0; oid < noids; oid++) {
97 newtbl = realloc(oidtbl, sizeof(struct obj *) * (noids + 1));
111 obj_free(struct obj *obj)
114 oidtbl[obj->oid] = NULL;
120 obj_lookup(int oid, u_int type)
124 if (oid < 0 || oid >= noids) {
129 if (obj->refcnt == 0) {
133 if (type != OBJ_TYPE_NONE && obj->type != type) {
141 bd_tag_new(struct obj *ptag, int fd, u_long align, u_long bndry,
142 u_long maxaddr, u_long maxsz, u_int nsegs, u_long maxsegsz,
143 u_int datarate, u_int flags)
145 struct proto_ioc_busdma ioc;
148 tag = obj_alloc(OBJ_TYPE_TAG);
152 memset(&ioc, 0, sizeof(ioc));
153 ioc.request = (ptag != NULL) ? PROTO_IOC_BUSDMA_TAG_DERIVE :
154 PROTO_IOC_BUSDMA_TAG_CREATE;
155 ioc.key = (ptag != NULL) ? ptag->key : 0;
156 ioc.u.tag.align = align;
157 ioc.u.tag.bndry = bndry;
158 ioc.u.tag.maxaddr = maxaddr;
159 ioc.u.tag.maxsz = maxsz;
160 ioc.u.tag.nsegs = nsegs;
161 ioc.u.tag.maxsegsz = maxsegsz;
162 ioc.u.tag.datarate = datarate;
163 ioc.u.tag.flags = flags;
164 if (ioctl(fd, PROTO_IOC_BUSDMA, &ioc) == -1) {
171 tag->key = ioc.result;
172 tag->u.tag.align = ioc.u.tag.align;
173 tag->u.tag.bndry = ioc.u.tag.bndry;
174 tag->u.tag.maxaddr = ioc.u.tag.maxaddr;
175 tag->u.tag.maxsz = ioc.u.tag.maxsz;
176 tag->u.tag.maxsegsz = ioc.u.tag.maxsegsz;
177 tag->u.tag.nsegs = ioc.u.tag.nsegs;
178 tag->u.tag.datarate = ioc.u.tag.datarate;
183 bd_tag_create(const char *dev, u_long align, u_long bndry, u_long maxaddr,
184 u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags)
189 fd = open(dev, O_RDWR);
193 tag = bd_tag_new(NULL, fd, align, bndry, maxaddr, maxsz, nsegs,
194 maxsegsz, datarate, flags);
203 bd_tag_derive(int ptid, u_long align, u_long bndry, u_long maxaddr,
204 u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags)
206 struct obj *ptag, *tag;
208 ptag = obj_lookup(ptid, OBJ_TYPE_TAG);
212 tag = bd_tag_new(ptag, ptag->fd, align, bndry, maxaddr, maxsz, nsegs,
213 maxsegsz, datarate, flags);
221 bd_tag_destroy(int tid)
223 struct proto_ioc_busdma ioc;
224 struct obj *ptag, *tag;
226 tag = obj_lookup(tid, OBJ_TYPE_TAG);
232 memset(&ioc, 0, sizeof(ioc));
233 ioc.request = PROTO_IOC_BUSDMA_TAG_DESTROY;
235 if (ioctl(tag->fd, PROTO_IOC_BUSDMA, &ioc) == -1)
238 if (tag->parent != NULL)
239 tag->parent->refcnt--;
247 bd_mem_alloc(int tid, u_int flags)
249 struct proto_ioc_busdma ioc;
250 struct obj *md, *tag;
251 struct obj *bseg, *pseg, *vseg;
253 tag = obj_lookup(tid, OBJ_TYPE_TAG);
257 md = obj_alloc(OBJ_TYPE_MD);
261 memset(&ioc, 0, sizeof(ioc));
262 ioc.request = PROTO_IOC_BUSDMA_MEM_ALLOC;
263 ioc.u.mem.tag = tag->key;
264 ioc.u.mem.flags = flags;
265 if (ioctl(tag->fd, PROTO_IOC_BUSDMA, &ioc) == -1) {
274 md->key = ioc.result;
276 /* XXX we need to support multiple segments */
277 assert(ioc.u.mem.phys_nsegs == 1);
278 assert(ioc.u.mem.bus_nsegs == 1);
280 bseg = pseg = vseg = NULL;
282 bseg = obj_alloc(OBJ_TYPE_SEG);
287 bseg->u.seg.address = ioc.u.mem.bus_addr;
288 bseg->u.seg.size = tag->u.tag.maxsz;
289 md->u.md.seg[BUSDMA_MD_BUS] = bseg;
290 md->u.md.nsegs[BUSDMA_MD_BUS] = ioc.u.mem.bus_nsegs;
292 pseg = obj_alloc(OBJ_TYPE_SEG);
297 pseg->u.seg.address = ioc.u.mem.phys_addr;
298 pseg->u.seg.size = tag->u.tag.maxsz;
299 md->u.md.seg[BUSDMA_MD_PHYS] = pseg;
300 md->u.md.nsegs[BUSDMA_MD_PHYS] = ioc.u.mem.phys_nsegs;
302 vseg = obj_alloc(OBJ_TYPE_SEG);
307 vseg->u.seg.address = (uintptr_t)mmap(NULL, pseg->u.seg.size,
308 PROT_READ | PROT_WRITE, MAP_NOCORE | MAP_SHARED, md->fd,
309 pseg->u.seg.address);
310 if (vseg->u.seg.address == (uintptr_t)MAP_FAILED)
312 vseg->u.seg.size = pseg->u.seg.size;
313 md->u.md.seg[BUSDMA_MD_VIRT] = vseg;
314 md->u.md.nsegs[BUSDMA_MD_VIRT] = 1;
325 memset(&ioc, 0, sizeof(ioc));
326 ioc.request = PROTO_IOC_BUSDMA_MEM_FREE;
328 ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc);
329 md->parent->refcnt--;
335 bd_mem_free(int mdid)
337 struct proto_ioc_busdma ioc;
338 struct obj *md, *seg, *seg0;
340 md = obj_lookup(mdid, OBJ_TYPE_MD);
344 for (seg = md->u.md.seg[BUSDMA_MD_VIRT]; seg != NULL; seg = seg0) {
345 munmap((void *)seg->u.seg.address, seg->u.seg.size);
346 seg0 = seg->u.seg.next;
349 for (seg = md->u.md.seg[BUSDMA_MD_PHYS]; seg != NULL; seg = seg0) {
350 seg0 = seg->u.seg.next;
353 for (seg = md->u.md.seg[BUSDMA_MD_BUS]; seg != NULL; seg = seg0) {
354 seg0 = seg->u.seg.next;
357 memset(&ioc, 0, sizeof(ioc));
358 ioc.request = PROTO_IOC_BUSDMA_MEM_FREE;
360 if (ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc) == -1)
363 md->parent->refcnt--;
369 bd_md_first_seg(int mdid, int space)
371 struct obj *md, *seg;
373 md = obj_lookup(mdid, OBJ_TYPE_MD);
377 if (space != BUSDMA_MD_BUS && space != BUSDMA_MD_PHYS &&
378 space != BUSDMA_MD_VIRT) {
382 seg = md->u.md.seg[space];
391 bd_md_next_seg(int mdid, int sid)
395 seg = obj_lookup(sid, OBJ_TYPE_SEG);
399 seg = seg->u.seg.next;
408 bd_seg_get_addr(int sid, u_long *addr_p)
415 seg = obj_lookup(sid, OBJ_TYPE_SEG);
419 *addr_p = seg->u.seg.address;
424 bd_seg_get_size(int sid, u_long *size_p)
431 seg = obj_lookup(sid, OBJ_TYPE_SEG);
435 *size_p = seg->u.seg.size;