summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2015-06-08 21:47:44 +0000
committermarcel <marcel@FreeBSD.org>2015-06-08 21:47:44 +0000
commit21b395f61276e9d47940a84cb4c9055ce8713596 (patch)
treee5243541b6953a7b29361b79720a6132bbb68a18
parent03d0a54e3cc610c487abdeeee2f71c2b564c215a (diff)
downloadFreeBSD-src-21b395f61276e9d47940a84cb4c9055ce8713596.zip
FreeBSD-src-21b395f61276e9d47940a84cb4c9055ce8713596.tar.gz
Implement mmap(2) for the busdma resource.
-rw-r--r--sys/dev/proto/proto_busdma.c20
-rw-r--r--sys/dev/proto/proto_busdma.h5
-rw-r--r--sys/dev/proto/proto_core.c26
3 files changed, 39 insertions, 12 deletions
diff --git a/sys/dev/proto/proto_busdma.c b/sys/dev/proto/proto_busdma.c
index 80d7e58..ced4eed 100644
--- a/sys/dev/proto/proto_busdma.c
+++ b/sys/dev/proto/proto_busdma.c
@@ -146,16 +146,17 @@ proto_busdma_mem_alloc(struct proto_busdma *busdma, struct proto_tag *tag,
free(md, M_PROTO_BUSDMA);
return (error);
}
- error = bus_dmamem_alloc(md->bd_tag, &md->kva, 0, &md->bd_map);
+ error = bus_dmamem_alloc(md->bd_tag, &md->virtaddr, 0, &md->bd_map);
if (error) {
bus_dma_tag_destroy(md->bd_tag);
free(md, M_PROTO_BUSDMA);
return (error);
}
+ md->physaddr = pmap_kextract((uintptr_t)(md->virtaddr));
LIST_INSERT_HEAD(&tag->mds, md, peers);
LIST_INSERT_HEAD(&busdma->mds, md, mds);
ioc->u.mem.nsegs = 1;
- ioc->u.mem.physaddr = pmap_kextract((uintptr_t)(md->kva));
+ ioc->u.mem.physaddr = md->physaddr;
ioc->result = (uintptr_t)(void *)md;
return (0);
}
@@ -166,7 +167,7 @@ proto_busdma_mem_free(struct proto_busdma *busdma, struct proto_md *md)
LIST_REMOVE(md, mds);
LIST_REMOVE(md, peers);
- bus_dmamem_free(md->bd_tag, md->kva, md->bd_map);
+ bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map);
bus_dma_tag_destroy(md->bd_tag);
free(md, M_PROTO_BUSDMA);
return (0);
@@ -267,3 +268,16 @@ proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
}
return (error);
}
+
+int
+proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr)
+{
+ struct proto_md *md;
+
+ LIST_FOREACH(md, &busdma->mds, mds) {
+ if (physaddr >= trunc_page(md->physaddr) &&
+ physaddr <= trunc_page(md->physaddr + md->tag->maxsz))
+ return (1);
+ }
+ return (0);
+}
diff --git a/sys/dev/proto/proto_busdma.h b/sys/dev/proto/proto_busdma.h
index d07046f..b4957f5 100644
--- a/sys/dev/proto/proto_busdma.h
+++ b/sys/dev/proto/proto_busdma.h
@@ -50,7 +50,8 @@ struct proto_md {
LIST_ENTRY(proto_md) mds;
LIST_ENTRY(proto_md) peers;
struct proto_tag *tag;
- void *kva;
+ void *virtaddr;
+ vm_paddr_t physaddr;
bus_dma_tag_t bd_tag;
bus_dmamap_t bd_map;
};
@@ -69,4 +70,6 @@ int proto_busdma_cleanup(struct proto_softc *, struct proto_busdma *);
int proto_busdma_ioctl(struct proto_softc *, struct proto_busdma *,
struct proto_ioc_busdma *);
+int proto_busdma_mmap_allowed(struct proto_busdma *, vm_paddr_t);
+
#endif /* _DEV_PROTO_BUSDMA_H_ */
diff --git a/sys/dev/proto/proto_core.c b/sys/dev/proto/proto_core.c
index 1b70cea..86f08eb 100644
--- a/sys/dev/proto/proto_core.c
+++ b/sys/dev/proto/proto_core.c
@@ -402,19 +402,29 @@ proto_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
{
struct proto_res *r;
- r = cdev->si_drv2;
-
- if (r->r_type != SYS_RES_MEMORY)
- return (ENXIO);
if (offset & PAGE_MASK)
return (EINVAL);
if (prot & PROT_EXEC)
return (EACCES);
- if (offset >= r->r_size)
- return (EINVAL);
- *paddr = rman_get_start(r->r_d.res) + offset;
+
+ r = cdev->si_drv2;
+
+ switch (r->r_type) {
+ case SYS_RES_MEMORY:
+ if (offset >= r->r_size)
+ return (EINVAL);
+ *paddr = rman_get_start(r->r_d.res) + offset;
#ifndef __sparc64__
- *memattr = VM_MEMATTR_UNCACHEABLE;
+ *memattr = VM_MEMATTR_UNCACHEABLE;
#endif
+ break;
+ case PROTO_RES_BUSDMA:
+ if (!proto_busdma_mmap_allowed(r->r_d.busdma, offset))
+ return (EINVAL);
+ *paddr = offset;
+ break;
+ default:
+ return (ENXIO);
+ }
return (0);
}
OpenPOWER on IntegriCloud