aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/proto/proto_busdma.c
diff options
context:
space:
mode:
authorMarcel Moolenaar <marcel@FreeBSD.org>2015-06-06 16:09:25 +0000
committerMarcel Moolenaar <marcel@FreeBSD.org>2015-06-06 16:09:25 +0000
commit4f027abddb02c5b6df045e359a96728b3cd7a09e (patch)
tree291e67893872baf40a02c4931357821f336b6929 /sys/dev/proto/proto_busdma.c
parentbbb169f2a4fc85cf470daf2f6dfffed545a5e7a7 (diff)
downloadsrc-4f027abddb02c5b6df045e359a96728b3cd7a09e.tar.gz
src-4f027abddb02c5b6df045e359a96728b3cd7a09e.zip
DMA support part 1: DMA tag create & destroy
Create a special resource (= device special file) for management of tags and maps, as well as for mapping memory into the address space. DMA resources are managed using the PROTO_IOC_BUSDMA ioctl. Part 1 implements tag creation, derivation and destruction.
Notes
Notes: svn path=/head/; revision=284079
Diffstat (limited to 'sys/dev/proto/proto_busdma.c')
-rw-r--r--sys/dev/proto/proto_busdma.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/sys/dev/proto/proto_busdma.c b/sys/dev/proto/proto_busdma.c
new file mode 100644
index 000000000000..90d953253e6f
--- /dev/null
+++ b/sys/dev/proto/proto_busdma.c
@@ -0,0 +1,167 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+#include <machine/bus_dma.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/rman.h>
+#include <sys/sbuf.h>
+
+#include <dev/proto/proto.h>
+#include <dev/proto/proto_dev.h>
+#include <dev/proto/proto_busdma.h>
+
+MALLOC_DEFINE(M_PROTO_BUSDMA, "proto_busdma", "DMA management data");
+
+static int
+proto_busdma_tag_create(struct proto_ioc_busdma *ioc,
+ struct proto_tag **tag_io, bus_dma_tag_t *busdma_tag_io)
+{
+ struct proto_tag *tag;
+ int error;
+
+ error = bus_dma_tag_create(*busdma_tag_io, ioc->u.tag.align,
+ ioc->u.tag.bndry, ioc->u.tag.maxaddr, BUS_SPACE_MAXADDR,
+ NULL, NULL, ioc->u.tag.maxsz, ioc->u.tag.nsegs,
+ ioc->u.tag.maxsegsz, ioc->u.tag.flags, NULL, NULL,
+ busdma_tag_io);
+ if (error)
+ return (error);
+
+ tag = malloc(sizeof(*tag), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
+ tag->parent = *tag_io;
+ tag->busdma_tag = *busdma_tag_io;
+ *tag_io = tag;
+ return (0);
+}
+
+static void
+proto_busdma_tag_destroy(struct proto_tag *tag)
+{
+
+ bus_dma_tag_destroy(tag->busdma_tag);
+ free(tag, M_PROTO_BUSDMA);
+}
+
+static struct proto_tag *
+proto_busdma_tag_lookup(struct proto_busdma *busdma, u_long key)
+{
+ struct proto_tag *tag;
+
+ LIST_FOREACH(tag, &busdma->tags, link) {
+ if ((void *)tag == (void *)key)
+ return (tag);
+ }
+ return (NULL);
+}
+
+struct proto_busdma *
+proto_busdma_attach(struct proto_softc *sc)
+{
+ struct proto_busdma *busdma;
+
+ busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
+ return (busdma);
+}
+
+int
+proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
+{
+
+ proto_busdma_cleanup(sc, busdma);
+ free(busdma, M_PROTO_BUSDMA);
+ return (0);
+}
+
+int
+proto_busdma_cleanup(struct proto_softc *sc, struct proto_busdma *busdma)
+{
+ struct proto_tag *tag, *tag1;
+
+ LIST_FOREACH_SAFE(tag, &busdma->tags, link, tag1) {
+ LIST_REMOVE(tag, link);
+ proto_busdma_tag_destroy(tag);
+ }
+ return (0);
+}
+
+int
+proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
+ struct proto_ioc_busdma *ioc)
+{
+ struct proto_tag *tag;
+ bus_dma_tag_t busdma_tag;
+ int error;
+
+ error = 0;
+ switch (ioc->request) {
+ case PROTO_IOC_BUSDMA_TAG_CREATE:
+ busdma_tag = bus_get_dma_tag(sc->sc_dev);
+ tag = NULL;
+ error = proto_busdma_tag_create(ioc, &tag, &busdma_tag);
+ if (error)
+ break;
+ LIST_INSERT_HEAD(&busdma->tags, tag, link);
+ ioc->key = (uintptr_t)(void *)tag;
+ break;
+ case PROTO_IOC_BUSDMA_TAG_DERIVE:
+ tag = proto_busdma_tag_lookup(busdma, ioc->key);
+ if (tag == NULL) {
+ error = EINVAL;
+ break;
+ }
+ busdma_tag = tag->busdma_tag;
+ error = proto_busdma_tag_create(ioc, &tag, &busdma_tag);
+ if (error)
+ break;
+ LIST_INSERT_HEAD(&busdma->tags, tag, link);
+ ioc->key = (uintptr_t)(void *)tag;
+ break;
+ case PROTO_IOC_BUSDMA_TAG_DESTROY:
+ tag = proto_busdma_tag_lookup(busdma, ioc->key);
+ if (tag == NULL) {
+ error = EINVAL;
+ break;
+ }
+ LIST_REMOVE(tag, link);
+ proto_busdma_tag_destroy(tag);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}