Index: head/tools/bus_space/C/lang.c =================================================================== --- head/tools/bus_space/C/lang.c (revision 285074) +++ head/tools/bus_space/C/lang.c (revision 285075) @@ -1,220 +1,234 @@ /*- * 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)); } int busdma_md_create(busdma_tag_t tag, u_int flags, busdma_md_t *out_p) { int res; res = bd_md_create(tag, flags); if (res == -1) return (errno); *out_p = res; return (0); } int busdma_md_destroy(busdma_md_t md) { return (bd_md_destroy(md)); } int busdma_md_load(busdma_md_t md, void *buf, size_t len, u_int flags) { return (bd_md_load(md, buf, len, flags)); } +int +busdma_md_unload(busdma_md_t md) +{ + + return (bd_md_unload(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); +} + +int +busdma_sync(busdma_md_t md, int op, bus_addr_t base, bus_size_t size) +{ + + return (bd_sync(md, op, base, size)); } Index: head/tools/bus_space/C/libbus.h =================================================================== --- head/tools/bus_space/C/libbus.h (revision 285074) +++ head/tools/bus_space/C/libbus.h (revision 285075) @@ -1,75 +1,83 @@ /*- * 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); int busdma_md_create(busdma_tag_t tag, u_int flags, busdma_md_t *out_p); int busdma_md_destroy(busdma_md_t md); int busdma_md_load(busdma_md_t md, void *buf, size_t len, u_int flags); +int busdma_md_unload(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); + +#define BUSDMA_SYNC_PREREAD 1 +#define BUSDMA_SYNC_POSTREAD 2 +#define BUSDMA_SYNC_PREWRITE 4 +#define BUSDMA_SYNC_POSTWRITE 8 + +int busdma_sync(busdma_md_t md, int op, bus_addr_t, bus_size_t); #endif /* _LIBBUS_SPACE_H_ */ Index: head/tools/bus_space/Python/lang.c =================================================================== --- head/tools/bus_space/Python/lang.c (revision 285074) +++ head/tools/bus_space/Python/lang.c (revision 285075) @@ -1,429 +1,477 @@ /*- * 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_md_create(PyObject *self, PyObject *args) { u_int flags; int error, mdid, tid; if (!PyArg_ParseTuple(args, "iI", &tid, &flags)) return (NULL); mdid = bd_md_create(tid, flags); if (mdid == -1) { PyErr_SetString(PyExc_IOError, strerror(errno)); return (NULL); } return (Py_BuildValue("i", mdid)); } static PyObject * busdma_md_destroy(PyObject *self, PyObject *args) { int error, mdid; if (!PyArg_ParseTuple(args, "i", &mdid)) return (NULL); error = bd_md_destroy(mdid); if (error) { PyErr_SetString(PyExc_IOError, strerror(error)); return (NULL); } Py_RETURN_NONE; } static PyObject * busdma_md_load(PyObject *self, PyObject *args) { void *buf; u_long len; u_int flags; int error, mdid; if (!PyArg_ParseTuple(args, "iwkI", &mdid, &buf, &len, &flags)) return (NULL); error = bd_md_load(mdid, buf, len, flags); if (error) { PyErr_SetString(PyExc_IOError, strerror(error)); return (NULL); } Py_RETURN_NONE; } static PyObject * +busdma_md_unload(PyObject *self, PyObject *args) +{ + int error, mdid; + + if (!PyArg_ParseTuple(args, "i", &mdid)) + return (NULL); + error = bd_md_unload(mdid); + 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); - } + if (sid == -1) + Py_RETURN_NONE; 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); - } + if (sid == -1) + Py_RETURN_NONE; 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 PyObject * +busdma_sync(PyObject *self, PyObject *args) +{ + u_long base, size; + int error, mdid, op; + + if (!PyArg_ParseTuple(args, "iikk", &mdid, &op, &base, &size)) + return (NULL); + error = bd_sync(mdid, op, base, size); + if (error) { + PyErr_SetString(PyExc_IOError, strerror(error)); + return (NULL); + } + Py_RETURN_NONE; +} + 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." }, { "md_create", busdma_md_create, METH_VARARGS, "Create a new and empty memory descriptor." }, { "md_destroy", busdma_md_destroy, METH_VARARGS, "Destroy a previously created memory descriptor." }, { "md_load", busdma_md_load, METH_VARARGS, "Load a buffer into a memory descriptor." }, + { "md_unload", busdma_md_unload, METH_VARARGS, + "Unload a memory descriptor." }, { "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." }, + + { "sync", busdma_sync, METH_VARARGS, + "Keep memory/caches coherent WRT to DMA." }, + { NULL, NULL, 0, NULL } }; PyMODINIT_FUNC initbus(void) { + PyObject *bus, *busdma; - Py_InitModule("bus", bus_methods); - Py_InitModule("busdma", busdma_methods); + bus = Py_InitModule("bus", bus_methods); + if (bus == NULL) + return; + busdma = Py_InitModule("busdma", busdma_methods); + if (busdma == NULL) + return; + PyModule_AddObject(bus, "dma", busdma); + + PyModule_AddObject(busdma, "MD_BUS_SPACE", Py_BuildValue("i", 0)); + PyModule_AddObject(busdma, "MD_PHYS_SPACE", Py_BuildValue("i", 1)); + PyModule_AddObject(busdma, "MD_VIRT_SPACE", Py_BuildValue("i", 2)); + + PyModule_AddObject(busdma, "SYNC_PREREAD", Py_BuildValue("i", 1)); + PyModule_AddObject(busdma, "SYNC_POSTREAD", Py_BuildValue("i", 2)); + PyModule_AddObject(busdma, "SYNC_PREWRITE", Py_BuildValue("i", 4)); + PyModule_AddObject(busdma, "SYNC_POSTWRITE", Py_BuildValue("i", 8)); } Index: head/tools/bus_space/busdma.c =================================================================== --- head/tools/bus_space/busdma.c (revision 285074) +++ head/tools/bus_space/busdma.c (revision 285075) @@ -1,511 +1,560 @@ /*- * 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 #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 { 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 = calloc(1, sizeof(struct obj)); obj->type = type; 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); } static 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); } static int bd_md_add_seg(struct obj *md, int type, u_long addr, u_long size) { struct obj *seg; seg = obj_alloc(OBJ_TYPE_SEG); if (seg == NULL) return (errno); seg->refcnt = 1; seg->parent = md; seg->u.seg.address = addr; seg->u.seg.size = size; md->u.md.seg[type] = seg; md->u.md.nsegs[type] = 1; return (0); } +static int +bd_md_del_segs(struct obj *md, int type, int unmap) +{ + struct obj *seg, *seg0; + + for (seg = md->u.md.seg[type]; seg != NULL; seg = seg0) { + if (unmap) + munmap((void *)seg->u.seg.address, seg->u.seg.size); + seg0 = seg->u.seg.next; + obj_free(seg); + } + return (0); +} + int bd_md_create(int tid, u_int flags) { struct proto_ioc_busdma ioc; struct obj *md, *tag; 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_MD_CREATE; ioc.u.md.tag = tag->key; ioc.u.md.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; return (md->oid); } int bd_md_destroy(int mdid) { struct proto_ioc_busdma ioc; struct obj *md; md = obj_lookup(mdid, OBJ_TYPE_MD); if (md == NULL) return (errno); memset(&ioc, 0, sizeof(ioc)); ioc.request = PROTO_IOC_BUSDMA_MD_DESTROY; 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_load(int mdid, void *buf, u_long len, u_int flags) { struct proto_ioc_busdma ioc; struct obj *md; int error; md = obj_lookup(mdid, OBJ_TYPE_MD); if (md == NULL) return (errno); memset(&ioc, 0, sizeof(ioc)); ioc.request = PROTO_IOC_BUSDMA_MD_LOAD; ioc.key = md->key; ioc.u.md.flags = flags; ioc.u.md.virt_addr = (uintptr_t)buf; ioc.u.md.virt_size = len; if (ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc) == -1) return (errno); printf("XXX: %s: phys(%d, %#lx), bus(%d, %#lx)\n", __func__, ioc.u.md.phys_nsegs, ioc.u.md.phys_addr, ioc.u.md.bus_nsegs, ioc.u.md.bus_addr); error = bd_md_add_seg(md, BUSDMA_MD_VIRT, ioc.u.md.virt_addr, len); error = bd_md_add_seg(md, BUSDMA_MD_PHYS, ioc.u.md.phys_addr, len); error = bd_md_add_seg(md, BUSDMA_MD_BUS, ioc.u.md.bus_addr, len); return (error); } int +bd_md_unload(int mdid) +{ + struct proto_ioc_busdma ioc; + struct obj *md; + int error; + + md = obj_lookup(mdid, OBJ_TYPE_MD); + if (md == NULL) + return (errno); + + memset(&ioc, 0, sizeof(ioc)); + ioc.request = PROTO_IOC_BUSDMA_MD_UNLOAD; + ioc.key = md->key; + if (ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc) == -1) + return (errno); + + bd_md_del_segs(md, BUSDMA_MD_VIRT, 0); + bd_md_del_segs(md, BUSDMA_MD_PHYS, 0); + bd_md_del_segs(md, BUSDMA_MD_BUS, 0); + return (0); +} + +int bd_mem_alloc(int tid, u_int flags) { struct proto_ioc_busdma ioc; struct obj *md, *tag; uintptr_t addr; int error; 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.md.tag = tag->key; ioc.u.md.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; printf("XXX: %s: phys(%d, %#lx), bus(%d, %#lx)\n", __func__, ioc.u.md.phys_nsegs, ioc.u.md.phys_addr, ioc.u.md.bus_nsegs, ioc.u.md.bus_addr); /* XXX we need to support multiple segments */ assert(ioc.u.md.phys_nsegs == 1); assert(ioc.u.md.bus_nsegs == 1); error = bd_md_add_seg(md, BUSDMA_MD_PHYS, ioc.u.md.phys_addr, tag->u.tag.maxsz); error = bd_md_add_seg(md, BUSDMA_MD_BUS, ioc.u.md.bus_addr, tag->u.tag.maxsz); addr = (uintptr_t)mmap(NULL, tag->u.tag.maxsz, PROT_READ | PROT_WRITE, MAP_NOCORE | MAP_SHARED, md->fd, ioc.u.md.phys_addr); if (addr == (uintptr_t)MAP_FAILED) goto fail; error = bd_md_add_seg(md, BUSDMA_MD_VIRT, addr, tag->u.tag.maxsz); return (md->oid); fail: 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, *seg0; + struct obj *md; md = obj_lookup(mdid, OBJ_TYPE_MD); if (md == NULL) return (errno); - 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; if (ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc) == -1) return (errno); + bd_md_del_segs(md, BUSDMA_MD_VIRT, 1); + bd_md_del_segs(md, BUSDMA_MD_PHYS, 0); + bd_md_del_segs(md, BUSDMA_MD_BUS, 0); 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); +} + +int +bd_sync(int mdid, u_int op, u_long base, u_long size) +{ + struct proto_ioc_busdma ioc; + struct obj *md; + + md = obj_lookup(mdid, OBJ_TYPE_MD); + if (md == NULL) + return (errno); + + memset(&ioc, 0, sizeof(ioc)); + ioc.request = PROTO_IOC_BUSDMA_SYNC; + ioc.key = md->key; + ioc.u.sync.op = op; + ioc.u.sync.base = base; + ioc.u.sync.size = size; + if (ioctl(md->fd, PROTO_IOC_BUSDMA, &ioc) == -1) + return (errno); + return (0); } Index: head/tools/bus_space/busdma.h =================================================================== --- head/tools/bus_space/busdma.h (revision 285074) +++ head/tools/bus_space/busdma.h (revision 285075) @@ -1,53 +1,56 @@ /*- * 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_md_create(int tid, u_int flags); int bd_md_destroy(int mdid); int bd_md_load(int mdid, void *buf, u_long len, u_int flags); +int bd_md_unload(int mdid); 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 *); + +int bd_sync(int mdid, u_int op, u_long base, u_long size); #endif /* _TOOLS_BUS_DMA_H_ */