summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2015-06-11 03:02:40 +0000
committermarcel <marcel@FreeBSD.org>2015-06-11 03:02:40 +0000
commit7e7e822da19cf60cf9de6df938781bc539018838 (patch)
tree899e80dd4c8ad46725550110001c6e815cdf616f /tools
parent4b0e592d9fbd3b0675f91a62d7897c125a2f8981 (diff)
downloadFreeBSD-src-7e7e822da19cf60cf9de6df938781bc539018838.zip
FreeBSD-src-7e7e822da19cf60cf9de6df938781bc539018838.tar.gz
Add accessor functions for iterating over segments. A segment
can be in bus address space, physical memory space or virtual memory space.
Diffstat (limited to 'tools')
-rw-r--r--tools/bus_space/C/lang.c37
-rw-r--r--tools/bus_space/C/libbus.h11
-rw-r--r--tools/bus_space/Python/lang.c73
-rw-r--r--tools/bus_space/busdma.c130
-rw-r--r--tools/bus_space/busdma.h6
5 files changed, 245 insertions, 12 deletions
diff --git a/tools/bus_space/C/lang.c b/tools/bus_space/C/lang.c
index bbb2bc7..345957e 100644
--- a/tools/bus_space/C/lang.c
+++ b/tools/bus_space/C/lang.c
@@ -155,3 +155,40 @@ busdma_mem_free(busdma_md_t md)
return (bd_mem_free(md));
}
+
+busdma_seg_t
+busdma_md_first_seg(busdma_md_t md, int space)
+{
+ busdma_seg_t seg;
+
+ seg = bd_md_first_seg(md, space);
+ return (seg);
+}
+
+busdma_seg_t
+busdma_md_next_seg(busdma_md_t md, busdma_seg_t seg)
+{
+
+ seg = bd_md_next_seg(md, seg);
+ return (seg);
+}
+
+bus_addr_t
+busdma_seg_get_addr(busdma_seg_t seg)
+{
+ u_long addr;
+ int error;
+
+ error = bd_seg_get_addr(seg, &addr);
+ return ((error) ? ~0UL : addr);
+}
+
+bus_size_t
+busdma_seg_get_size(busdma_seg_t seg)
+{
+ u_long size;
+ int error;
+
+ error = bd_seg_get_size(seg, &size);
+ return ((error) ? ~0UL : size);
+}
diff --git a/tools/bus_space/C/libbus.h b/tools/bus_space/C/libbus.h
index 3574372..76ab402 100644
--- a/tools/bus_space/C/libbus.h
+++ b/tools/bus_space/C/libbus.h
@@ -43,6 +43,7 @@ typedef unsigned long bus_addr_t;
typedef unsigned long bus_size_t;
typedef int busdma_tag_t;
typedef int busdma_md_t;
+typedef int busdma_seg_t;
int busdma_tag_create(const char *dev, bus_addr_t align, bus_addr_t bndry,
bus_addr_t maxaddr, bus_size_t maxsz, u_int nsegs,
@@ -57,4 +58,14 @@ int busdma_tag_destroy(busdma_tag_t tag);
int busdma_mem_alloc(busdma_tag_t tag, u_int flags, busdma_md_t *out_p);
int busdma_mem_free(busdma_md_t md);
+#define BUSDMA_MD_BUS_SPACE 0
+#define BUSDMA_MD_PHYS_SPACE 1
+#define BUSDMA_MD_VIRT_SPACE 2
+
+int busdma_md_first_seg(busdma_md_t, int space);
+int busdma_md_next_seg(busdma_md_t, busdma_seg_t seg);
+
+bus_addr_t busdma_seg_get_addr(busdma_seg_t seg);
+bus_size_t busdma_seg_get_size(busdma_seg_t seg);
+
#endif /* _LIBBUS_SPACE_H_ */
diff --git a/tools/bus_space/Python/lang.c b/tools/bus_space/Python/lang.c
index d119b99..2127df5 100644
--- a/tools/bus_space/Python/lang.c
+++ b/tools/bus_space/Python/lang.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Marcel Moolenaar
+ * Copyright (c) 2014, 2015 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -259,6 +259,68 @@ busdma_mem_free(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
+static PyObject *
+busdma_md_first_seg(PyObject *self, PyObject *args)
+{
+ int error, mdid, sid, what;
+
+ if (!PyArg_ParseTuple(args, "ii", &mdid, &what))
+ return (NULL);
+ sid = bd_md_first_seg(mdid, what);
+ if (sid == -1) {
+ PyErr_SetString(PyExc_IOError, strerror(errno));
+ return (NULL);
+ }
+ return (Py_BuildValue("i", sid));
+}
+
+static PyObject *
+busdma_md_next_seg(PyObject *self, PyObject *args)
+{
+ int error, mdid, sid;
+
+ if (!PyArg_ParseTuple(args, "ii", &mdid, &sid))
+ return (NULL);
+ sid = bd_md_next_seg(mdid, sid);
+ if (sid == -1) {
+ PyErr_SetString(PyExc_IOError, strerror(errno));
+ return (NULL);
+ }
+ return (Py_BuildValue("i", sid));
+}
+
+static PyObject *
+busdma_seg_get_addr(PyObject *self, PyObject *args)
+{
+ u_long addr;
+ int error, sid;
+
+ if (!PyArg_ParseTuple(args, "i", &sid))
+ return (NULL);
+ error = bd_seg_get_addr(sid, &addr);
+ if (error) {
+ PyErr_SetString(PyExc_IOError, strerror(error));
+ return (NULL);
+ }
+ return (Py_BuildValue("k", addr));
+}
+
+static PyObject *
+busdma_seg_get_size(PyObject *self, PyObject *args)
+{
+ u_long size;
+ int error, sid;
+
+ if (!PyArg_ParseTuple(args, "i", &sid))
+ return (NULL);
+ error = bd_seg_get_size(sid, &size);
+ if (error) {
+ PyErr_SetString(PyExc_IOError, strerror(error));
+ return (NULL);
+ }
+ return (Py_BuildValue("k", size));
+}
+
static PyMethodDef bus_methods[] = {
{ "read_1", bus_read_1, METH_VARARGS, "Read a 1-byte data item." },
{ "read_2", bus_read_2, METH_VARARGS, "Read a 2-byte data item." },
@@ -289,6 +351,15 @@ static PyMethodDef busdma_methods[] = {
"Allocate memory according to the DMA constraints." },
{ "mem_free", busdma_mem_free, METH_VARARGS,
"Free allocated memory." },
+
+ { "md_first_seg", busdma_md_first_seg, METH_VARARGS,
+ "Return first segment in one of the segment lists." },
+ { "md_next_seg", busdma_md_next_seg, METH_VARARGS,
+ "Return next segment in the segment list." },
+ { "seg_get_addr", busdma_seg_get_addr, METH_VARARGS,
+ "Return the address of the segment." },
+ { "seg_get_size", busdma_seg_get_size, METH_VARARGS,
+ "Return the size of the segment." },
{ NULL, NULL, 0, NULL }
};
diff --git a/tools/bus_space/busdma.c b/tools/bus_space/busdma.c
index 4c6e37c..a710c78 100644
--- a/tools/bus_space/busdma.c
+++ b/tools/bus_space/busdma.c
@@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -46,6 +47,7 @@ struct obj {
#define OBJ_TYPE_NONE 0
#define OBJ_TYPE_TAG 1
#define OBJ_TYPE_MD 2
+#define OBJ_TYPE_SEG 3
u_int refcnt;
int fd;
struct obj *parent;
@@ -61,9 +63,17 @@ struct obj {
unsigned long datarate;
} tag;
struct {
- unsigned long physaddr;
- void *virtaddr;
- } mem;
+ struct obj *seg[3];
+ int nsegs[3];
+#define BUSDMA_MD_BUS 0
+#define BUSDMA_MD_PHYS 1
+#define BUSDMA_MD_VIRT 2
+ } md;
+ struct {
+ struct obj *next;
+ unsigned long address;
+ unsigned long size;
+ } seg;
} u;
};
@@ -76,9 +86,8 @@ obj_alloc(u_int type)
struct obj **newtbl, *obj;
int oid;
- obj = malloc(sizeof(struct obj));
+ obj = calloc(1, sizeof(struct obj));
obj->type = type;
- obj->refcnt = 0;
for (oid = 0; oid < noids; oid++) {
if (oidtbl[oid] == 0)
@@ -239,6 +248,7 @@ bd_mem_alloc(int tid, u_int flags)
{
struct proto_ioc_busdma ioc;
struct obj *md, *tag;
+ struct obj *bseg, *pseg, *vseg;
tag = obj_lookup(tid, OBJ_TYPE_TAG);
if (tag == NULL)
@@ -262,10 +272,35 @@ bd_mem_alloc(int tid, u_int flags)
md->parent = tag;
tag->refcnt++;
md->key = ioc.result;
- md->u.mem.physaddr = ioc.u.mem.physaddr;
- md->u.mem.virtaddr = mmap(NULL, tag->u.tag.maxsz,
+
+ 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 = obj_alloc(OBJ_TYPE_SEG);
+ bseg->refcnt = 1;
+ bseg->parent = md;
+ bseg->u.seg.address = ioc.u.mem.bus_addr;
+ bseg->u.seg.size = tag->u.tag.maxsz;
+ md->u.md.seg[BUSDMA_MD_BUS] = bseg;
+ md->u.md.nsegs[BUSDMA_MD_BUS] = ioc.u.mem.bus_nsegs;
+
+ vseg = obj_alloc(OBJ_TYPE_SEG);
+ 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,
- md->u.mem.physaddr);
+ pseg->u.seg.address);
+ 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);
}
@@ -273,14 +308,16 @@ int
bd_mem_free(int mdid)
{
struct proto_ioc_busdma ioc;
- struct obj *md;
+ struct obj *md, *seg;
md = obj_lookup(mdid, OBJ_TYPE_MD);
if (md == NULL)
return (errno);
- if (md->u.mem.virtaddr != MAP_FAILED)
- munmap(md->u.mem.virtaddr, md->parent->u.tag.maxsz);
+ for (seg = md->u.md.seg[BUSDMA_MD_VIRT];
+ seg != NULL;
+ seg = seg->u.seg.next)
+ munmap((void *)seg->u.seg.address, seg->u.seg.size);
memset(&ioc, 0, sizeof(ioc));
ioc.request = PROTO_IOC_BUSDMA_MEM_FREE;
ioc.key = md->key;
@@ -291,3 +328,74 @@ bd_mem_free(int mdid)
obj_free(md);
return (0);
}
+
+int
+bd_md_first_seg(int mdid, int space)
+{
+ struct obj *md, *seg;
+
+ md = obj_lookup(mdid, OBJ_TYPE_MD);
+ if (md == NULL)
+ return (-1);
+
+ if (space != BUSDMA_MD_BUS && space != BUSDMA_MD_PHYS &&
+ space != BUSDMA_MD_VIRT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ seg = md->u.md.seg[space];
+ if (seg == NULL) {
+ errno = ENXIO;
+ return (-1);
+ }
+ return (seg->oid);
+}
+
+int
+bd_md_next_seg(int mdid, int sid)
+{
+ struct obj *seg;
+
+ seg = obj_lookup(sid, OBJ_TYPE_SEG);
+ if (seg == NULL)
+ return (-1);
+
+ seg = seg->u.seg.next;
+ if (seg == NULL) {
+ errno = ENXIO;
+ return (-1);
+ }
+ return (seg->oid);
+}
+
+int
+bd_seg_get_addr(int sid, u_long *addr_p)
+{
+ struct obj *seg;
+
+ if (addr_p == NULL)
+ return (EINVAL);
+
+ seg = obj_lookup(sid, OBJ_TYPE_SEG);
+ if (seg == NULL)
+ return (errno);
+
+ *addr_p = seg->u.seg.address;
+ return (0);
+}
+
+int
+bd_seg_get_size(int sid, u_long *size_p)
+{
+ struct obj *seg;
+
+ if (size_p == NULL)
+ return (EINVAL);
+
+ seg = obj_lookup(sid, OBJ_TYPE_SEG);
+ if (seg == NULL)
+ return (errno);
+
+ *size_p = seg->u.seg.size;
+ return (0);
+}
diff --git a/tools/bus_space/busdma.h b/tools/bus_space/busdma.h
index 357cb30..7394b26 100644
--- a/tools/bus_space/busdma.h
+++ b/tools/bus_space/busdma.h
@@ -40,4 +40,10 @@ int bd_tag_destroy(int tid);
int bd_mem_alloc(int tid, u_int flags);
int bd_mem_free(int mdid);
+int bd_md_first_seg(int mdid, int what);
+int bd_md_next_seg(int mdid, int sid);
+
+int bd_seg_get_addr(int sid, u_long *);
+int bd_seg_get_size(int sid, u_long *);
+
#endif /* _TOOLS_BUS_DMA_H_ */
OpenPOWER on IntegriCloud