diff --git a/tools/bus_space/C/lang.c b/tools/bus_space/C/lang.c index bbb2bc7faa91..345957efdbe7 100644 --- a/tools/bus_space/C/lang.c +++ b/tools/bus_space/C/lang.c @@ -1,157 +1,194 @@ /*- * Copyright (c) 2014 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include "bus.h" #include "busdma.h" #include "libbus.h" int16_t bus_read_1(int rid, long ofs) { uint8_t val; return ((!bs_read(rid, ofs, &val, sizeof(val))) ? -1 : (int)val); } int32_t bus_read_2(int rid, long ofs) { uint16_t val; return ((!bs_read(rid, ofs, &val, sizeof(val))) ? -1 : (int)val); } int64_t bus_read_4(int rid, long ofs) { uint32_t val; return ((!bs_read(rid, ofs, &val, sizeof(val))) ? -1 : (int64_t)val); } int bus_write_1(int rid, long ofs, uint8_t val) { return ((!bs_write(rid, ofs, &val, sizeof(val))) ? errno : 0); } int bus_write_2(int rid, long ofs, uint16_t val) { return ((!bs_write(rid, ofs, &val, sizeof(val))) ? errno : 0); } int bus_write_4(int rid, long ofs, uint32_t val) { return ((!bs_write(rid, ofs, &val, sizeof(val))) ? errno : 0); } int bus_map(const char *dev) { return (bs_map(dev)); } int bus_unmap(int rid) { return ((!bs_unmap(rid)) ? errno : 0); } int bus_subregion(int rid, long ofs, long sz) { return (bs_subregion(rid, ofs, sz)); } 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, bus_size_t maxsegsz, u_int datarate, u_int flags, busdma_tag_t *out_p) { int res; res = bd_tag_create(dev, align, bndry, maxaddr, maxsz, nsegs, maxsegsz, datarate, flags); if (res == -1) return (errno); *out_p = res; return (0); } int busdma_tag_derive(busdma_tag_t tag, bus_addr_t align, bus_addr_t bndry, bus_addr_t maxaddr, bus_size_t maxsz, u_int nsegs, bus_size_t maxsegsz, u_int datarate, u_int flags, busdma_tag_t *out_p) { int res; res = bd_tag_derive(tag, align, bndry, maxaddr, maxsz, nsegs, maxsegsz, datarate, flags); if (res == -1) return (errno); *out_p = res; return (0); } int busdma_tag_destroy(busdma_tag_t tag) { return (bd_tag_destroy(tag)); } int busdma_mem_alloc(busdma_tag_t tag, u_int flags, busdma_md_t *out_p) { int res; res = bd_mem_alloc(tag, flags); if (res == -1) return (errno); *out_p = res; return (0); } int 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 357437246f8d..76ab40225145 100644 --- a/tools/bus_space/C/libbus.h +++ b/tools/bus_space/C/libbus.h @@ -1,60 +1,71 @@ /*- * Copyright (c) 2014, 2015 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _LIBBUS_SPACE_H_ #define _LIBBUS_SPACE_H_ int bus_map(const char *dev); int16_t bus_read_1(int rid, long ofs); int32_t bus_read_2(int rid, long ofs); int64_t bus_read_4(int rid, long ofs); int bus_subregion(int rid, long ofs, long sz); int bus_unmap(int rid); int bus_write_1(int rid, long ofs, uint8_t val); int bus_write_2(int rid, long ofs, uint16_t val); int bus_write_4(int rid, long ofs, uint32_t val); 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, bus_size_t maxsegsz, u_int datarate, u_int flags, busdma_tag_t *out_p); int busdma_tag_derive(busdma_tag_t tag, bus_addr_t align, bus_addr_t bndry, bus_addr_t maxaddr, bus_size_t maxsz, u_int nsegs, bus_size_t maxsegsz, u_int datarate, u_int flags, busdma_tag_t *out_p); 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 d119b999ebed..2127df57fa4f 100644 --- a/tools/bus_space/Python/lang.c +++ b/tools/bus_space/Python/lang.c @@ -1,301 +1,372 @@ /*- - * 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 * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include "bus.h" #include "busdma.h" static PyObject * bus_read_1(PyObject *self, PyObject *args) { long ofs; int rid; uint8_t val; if (!PyArg_ParseTuple(args, "il", &rid, &ofs)) return (NULL); if (!bs_read(rid, ofs, &val, sizeof(val))) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("B", val)); } static PyObject * bus_read_2(PyObject *self, PyObject *args) { long ofs; int rid; uint16_t val; if (!PyArg_ParseTuple(args, "il", &rid, &ofs)) return (NULL); if (!bs_read(rid, ofs, &val, sizeof(val))) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("H", val)); } static PyObject * bus_read_4(PyObject *self, PyObject *args) { long ofs; int rid; uint32_t val; if (!PyArg_ParseTuple(args, "il", &rid, &ofs)) return (NULL); if (!bs_read(rid, ofs, &val, sizeof(val))) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("I", val)); } static PyObject * bus_write_1(PyObject *self, PyObject *args) { long ofs; int rid; uint8_t val; if (!PyArg_ParseTuple(args, "ilB", &rid, &ofs, &val)) return (NULL); if (!bs_write(rid, ofs, &val, sizeof(val))) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } Py_RETURN_NONE; } static PyObject * bus_write_2(PyObject *self, PyObject *args) { long ofs; int rid; uint16_t val; if (!PyArg_ParseTuple(args, "ilH", &rid, &ofs, &val)) return (NULL); if (!bs_write(rid, ofs, &val, sizeof(val))) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } Py_RETURN_NONE; } static PyObject * bus_write_4(PyObject *self, PyObject *args) { long ofs; int rid; uint32_t val; if (!PyArg_ParseTuple(args, "ilI", &rid, &ofs, &val)) return (NULL); if (!bs_write(rid, ofs, &val, sizeof(val))) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } Py_RETURN_NONE; } static PyObject * bus_map(PyObject *self, PyObject *args) { char *dev; int rid; if (!PyArg_ParseTuple(args, "s", &dev)) return (NULL); rid = bs_map(dev); if (rid == -1) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("i", rid)); } static PyObject * bus_unmap(PyObject *self, PyObject *args) { int rid; if (!PyArg_ParseTuple(args, "i", &rid)) return (NULL); if (!bs_unmap(rid)) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } Py_RETURN_NONE; } static PyObject * bus_subregion(PyObject *self, PyObject *args) { long ofs, sz; int rid0, rid; if (!PyArg_ParseTuple(args, "ill", &rid0, &ofs, &sz)) return (NULL); rid = bs_subregion(rid0, ofs, sz); if (rid == -1) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("i", rid)); } static PyObject * busdma_tag_create(PyObject *self, PyObject *args) { char *dev; u_long align, bndry, maxaddr, maxsz, maxsegsz; u_int nsegs, datarate, flags; int tid; if (!PyArg_ParseTuple(args, "skkkkIkII", &dev, &align, &bndry, &maxaddr, &maxsz, &nsegs, &maxsegsz, &datarate, &flags)) return (NULL); tid = bd_tag_create(dev, align, bndry, maxaddr, maxsz, nsegs, maxsegsz, datarate, flags); if (tid == -1) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("i", tid)); } static PyObject * busdma_tag_derive(PyObject *self, PyObject *args) { u_long align, bndry, maxaddr, maxsz, maxsegsz; u_int nsegs, datarate, flags; int ptid, tid; if (!PyArg_ParseTuple(args, "ikkkkIkII", &ptid, &align, &bndry, &maxaddr, &maxsz, &nsegs, &maxsegsz, &datarate, &flags)) return (NULL); tid = bd_tag_derive(ptid, align, bndry, maxaddr, maxsz, nsegs, maxsegsz, datarate, flags); if (tid == -1) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("i", tid)); } static PyObject * busdma_tag_destroy(PyObject *self, PyObject *args) { int error, tid; if (!PyArg_ParseTuple(args, "i", &tid)) return (NULL); error = bd_tag_destroy(tid); if (error) { PyErr_SetString(PyExc_IOError, strerror(error)); return (NULL); } Py_RETURN_NONE; } static PyObject * busdma_mem_alloc(PyObject *self, PyObject *args) { u_int flags; int mdid, tid; if (!PyArg_ParseTuple(args, "iI", &tid, &flags)) return (NULL); mdid = bd_mem_alloc(tid, flags); if (mdid == -1) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("i", mdid)); } static PyObject * busdma_mem_free(PyObject *self, PyObject *args) { int error, mdid; if (!PyArg_ParseTuple(args, "i", &mdid)) return (NULL); error = bd_mem_free(mdid); if (error) { PyErr_SetString(PyExc_IOError, strerror(error)); return (NULL); } 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." }, { "read_4", bus_read_4, METH_VARARGS, "Read a 4-byte data item." }, { "write_1", bus_write_1, METH_VARARGS, "Write a 1-byte data item." }, { "write_2", bus_write_2, METH_VARARGS, "Write a 2-byte data item." }, { "write_4", bus_write_4, METH_VARARGS, "Write a 4-byte data item." }, { "map", bus_map, METH_VARARGS, "Return a resource ID for a device file created by proto(4)" }, { "unmap", bus_unmap, METH_VARARGS, "Free a resource ID" }, { "subregion", bus_subregion, METH_VARARGS, "Return a resource ID for a subregion of another resource ID" }, { NULL, NULL, 0, NULL } }; static PyMethodDef busdma_methods[] = { { "tag_create", busdma_tag_create, METH_VARARGS, "Create a root tag." }, { "tag_derive", busdma_tag_derive, METH_VARARGS, "Derive a child tag." }, { "tag_destroy", busdma_tag_destroy, METH_VARARGS, "Destroy a tag." }, { "mem_alloc", busdma_mem_alloc, METH_VARARGS, "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 } }; PyMODINIT_FUNC initbus(void) { Py_InitModule("bus", bus_methods); Py_InitModule("busdma", busdma_methods); } diff --git a/tools/bus_space/busdma.c b/tools/bus_space/busdma.c index 4c6e37cca536..a710c78b4dd1 100644 --- a/tools/bus_space/busdma.c +++ b/tools/bus_space/busdma.c @@ -1,293 +1,401 @@ /*- * Copyright (c) 2015 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include #include #include #include #include "busdma.h" #include "../../sys/dev/proto/proto_dev.h" struct obj { int oid; u_int type; #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; u_long key; union { struct { unsigned long align; unsigned long bndry; unsigned long maxaddr; unsigned long maxsz; unsigned long maxsegsz; unsigned long nsegs; 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; }; static struct obj **oidtbl = NULL; static int noids = 0; static struct obj * 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) break; } if (oid == noids) { newtbl = realloc(oidtbl, sizeof(struct obj *) * (noids + 1)); if (newtbl == NULL) { free(obj); return (NULL); } oidtbl = newtbl; noids++; } oidtbl[oid] = obj; obj->oid = oid; return (obj); } static int obj_free(struct obj *obj) { oidtbl[obj->oid] = NULL; free(obj); return (0); } static struct obj * obj_lookup(int oid, u_int type) { struct obj *obj; if (oid < 0 || oid >= noids) { errno = EINVAL; return (NULL); } obj = oidtbl[oid]; if (obj->refcnt == 0) { errno = ENXIO; return (NULL); } if (type != OBJ_TYPE_NONE && obj->type != type) { errno = ENODEV; return (NULL); } return (obj); } struct obj * bd_tag_new(struct obj *ptag, int fd, u_long align, u_long bndry, u_long maxaddr, u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags) { struct proto_ioc_busdma ioc; struct obj *tag; tag = obj_alloc(OBJ_TYPE_TAG); if (tag == NULL) return (NULL); memset(&ioc, 0, sizeof(ioc)); ioc.request = (ptag != NULL) ? PROTO_IOC_BUSDMA_TAG_DERIVE : PROTO_IOC_BUSDMA_TAG_CREATE; ioc.key = (ptag != NULL) ? ptag->key : 0; ioc.u.tag.align = align; ioc.u.tag.bndry = bndry; ioc.u.tag.maxaddr = maxaddr; ioc.u.tag.maxsz = maxsz; ioc.u.tag.nsegs = nsegs; ioc.u.tag.maxsegsz = maxsegsz; ioc.u.tag.datarate = datarate; ioc.u.tag.flags = flags; if (ioctl(fd, PROTO_IOC_BUSDMA, &ioc) == -1) { obj_free(tag); return (NULL); } tag->refcnt = 1; tag->fd = fd; tag->parent = ptag; tag->key = ioc.result; tag->u.tag.align = ioc.u.tag.align; tag->u.tag.bndry = ioc.u.tag.bndry; tag->u.tag.maxaddr = ioc.u.tag.maxaddr; tag->u.tag.maxsz = ioc.u.tag.maxsz; tag->u.tag.maxsegsz = ioc.u.tag.maxsegsz; tag->u.tag.nsegs = ioc.u.tag.nsegs; tag->u.tag.datarate = ioc.u.tag.datarate; return (tag); } int bd_tag_create(const char *dev, u_long align, u_long bndry, u_long maxaddr, u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags) { struct obj *tag; int fd; fd = open(dev, O_RDWR); if (fd == -1) return (-1); tag = bd_tag_new(NULL, fd, align, bndry, maxaddr, maxsz, nsegs, maxsegsz, datarate, flags); if (tag == NULL) { close(fd); return (-1); } return (tag->oid); } int bd_tag_derive(int ptid, u_long align, u_long bndry, u_long maxaddr, u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags) { struct obj *ptag, *tag; ptag = obj_lookup(ptid, OBJ_TYPE_TAG); if (ptag == NULL) return (-1); tag = bd_tag_new(ptag, ptag->fd, align, bndry, maxaddr, maxsz, nsegs, maxsegsz, datarate, flags); if (tag == NULL) return (-1); ptag->refcnt++; return (tag->oid); } int bd_tag_destroy(int tid) { struct proto_ioc_busdma ioc; struct obj *ptag, *tag; tag = obj_lookup(tid, OBJ_TYPE_TAG); if (tag == NULL) return (errno); if (tag->refcnt > 1) return (EBUSY); memset(&ioc, 0, sizeof(ioc)); ioc.request = PROTO_IOC_BUSDMA_TAG_DESTROY; ioc.key = tag->key; if (ioctl(tag->fd, PROTO_IOC_BUSDMA, &ioc) == -1) return (errno); if (tag->parent != NULL) tag->parent->refcnt--; else close(tag->fd); obj_free(tag); return (0); } int 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) return (-1); md = obj_alloc(OBJ_TYPE_MD); if (md == NULL) return (-1); memset(&ioc, 0, sizeof(ioc)); ioc.request = PROTO_IOC_BUSDMA_MEM_ALLOC; ioc.u.mem.tag = tag->key; ioc.u.mem.flags = flags; if (ioctl(tag->fd, PROTO_IOC_BUSDMA, &ioc) == -1) { obj_free(md); return (-1); } md->refcnt = 1; md->fd = tag->fd; 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); } 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; if (ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc) == -1) return (errno); md->parent->refcnt--; 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 357cb3042588..7394b267fcdc 100644 --- a/tools/bus_space/busdma.h +++ b/tools/bus_space/busdma.h @@ -1,43 +1,49 @@ /*- * Copyright (c) 2015 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _TOOLS_BUS_DMA_H_ #define _TOOLS_BUS_DMA_H_ int bd_tag_create(const char *dev, u_long align, u_long bndry, u_long maxaddr, u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags); int bd_tag_derive(int tid, u_long align, u_long bndry, u_long maxaddr, u_long maxsz, u_int nsegs, u_long maxsegsz, u_int datarate, u_int flags); 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_ */