summaryrefslogtreecommitdiffstats
path: root/tools/bus_space
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2015-06-12 14:53:56 +0000
committermarcel <marcel@FreeBSD.org>2015-06-12 14:53:56 +0000
commit71bc1e1d8b95143fd418a75d05c6b279558cec3f (patch)
treee422376eb19a9f339e167dd1be306c30f5091f20 /tools/bus_space
parent484f91b8a54423887a3613b362c8023a96922f58 (diff)
downloadFreeBSD-src-71bc1e1d8b95143fd418a75d05c6b279558cec3f.zip
FreeBSD-src-71bc1e1d8b95143fd418a75d05c6b279558cec3f.tar.gz
Free the segment objects properly.
Diffstat (limited to 'tools/bus_space')
-rw-r--r--tools/bus_space/busdma.c60
1 files changed, 48 insertions, 12 deletions
diff --git a/tools/bus_space/busdma.c b/tools/bus_space/busdma.c
index a710c78..e1e5a00 100644
--- a/tools/bus_space/busdma.c
+++ b/tools/bus_space/busdma.c
@@ -273,17 +273,15 @@ bd_mem_alloc(int tid, u_int flags)
tag->refcnt++;
md->key = ioc.result;
+ /* XXX we need to support multiple segments */
assert(ioc.u.mem.phys_nsegs == 1);
- pseg = obj_alloc(OBJ_TYPE_SEG);
- pseg->refcnt = 1;
- pseg->parent = md;
- pseg->u.seg.address = ioc.u.mem.phys_addr;
- pseg->u.seg.size = tag->u.tag.maxsz;
- md->u.md.seg[BUSDMA_MD_PHYS] = pseg;
- md->u.md.nsegs[BUSDMA_MD_PHYS] = ioc.u.mem.phys_nsegs;
-
assert(ioc.u.mem.bus_nsegs == 1);
+
+ bseg = pseg = vseg = NULL;
+
bseg = obj_alloc(OBJ_TYPE_SEG);
+ if (bseg == NULL)
+ goto fail;
bseg->refcnt = 1;
bseg->parent = md;
bseg->u.seg.address = ioc.u.mem.bus_addr;
@@ -291,33 +289,71 @@ bd_mem_alloc(int tid, u_int flags)
md->u.md.seg[BUSDMA_MD_BUS] = bseg;
md->u.md.nsegs[BUSDMA_MD_BUS] = ioc.u.mem.bus_nsegs;
+ pseg = obj_alloc(OBJ_TYPE_SEG);
+ if (pseg == NULL)
+ goto fail;
+ pseg->refcnt = 1;
+ pseg->parent = md;
+ pseg->u.seg.address = ioc.u.mem.phys_addr;
+ pseg->u.seg.size = tag->u.tag.maxsz;
+ md->u.md.seg[BUSDMA_MD_PHYS] = pseg;
+ md->u.md.nsegs[BUSDMA_MD_PHYS] = ioc.u.mem.phys_nsegs;
+
vseg = obj_alloc(OBJ_TYPE_SEG);
+ if (vseg == NULL)
+ goto fail;
vseg->refcnt = 1;
vseg->parent = md;
vseg->u.seg.address = (uintptr_t)mmap(NULL, pseg->u.seg.size,
PROT_READ | PROT_WRITE, MAP_NOCORE | MAP_SHARED, md->fd,
pseg->u.seg.address);
+ if (vseg->u.seg.address == (uintptr_t)MAP_FAILED)
+ goto fail;
vseg->u.seg.size = pseg->u.seg.size;
md->u.md.seg[BUSDMA_MD_VIRT] = vseg;
md->u.md.nsegs[BUSDMA_MD_VIRT] = 1;
return (md->oid);
+
+ fail:
+ if (vseg != NULL)
+ obj_free(vseg);
+ if (pseg != NULL)
+ obj_free(pseg);
+ if (bseg != NULL)
+ obj_free(bseg);
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.request = PROTO_IOC_BUSDMA_MEM_FREE;
+ ioc.key = md->key;
+ ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc);
+ md->parent->refcnt--;
+ obj_free(md);
+ return (-1);
}
int
bd_mem_free(int mdid)
{
struct proto_ioc_busdma ioc;
- struct obj *md, *seg;
+ struct obj *md, *seg, *seg0;
md = obj_lookup(mdid, OBJ_TYPE_MD);
if (md == NULL)
return (errno);
- for (seg = md->u.md.seg[BUSDMA_MD_VIRT];
- seg != NULL;
- seg = seg->u.seg.next)
+ for (seg = md->u.md.seg[BUSDMA_MD_VIRT]; seg != NULL; seg = seg0) {
munmap((void *)seg->u.seg.address, seg->u.seg.size);
+ seg0 = seg->u.seg.next;
+ obj_free(seg);
+ }
+ for (seg = md->u.md.seg[BUSDMA_MD_PHYS]; seg != NULL; seg = seg0) {
+ seg0 = seg->u.seg.next;
+ obj_free(seg);
+ }
+ for (seg = md->u.md.seg[BUSDMA_MD_BUS]; seg != NULL; seg = seg0) {
+ seg0 = seg->u.seg.next;
+ obj_free(seg);
+ }
memset(&ioc, 0, sizeof(ioc));
ioc.request = PROTO_IOC_BUSDMA_MEM_FREE;
ioc.key = md->key;
OpenPOWER on IntegriCloud