Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 6 Jun 2015 16:09:25 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r284079 - head/sys/dev/proto
Message-ID:  <201506061609.t56G9P66021328@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Sat Jun  6 16:09:25 2015
New Revision: 284079
URL: https://svnweb.freebsd.org/changeset/base/284079

Log:
  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.

Added:
  head/sys/dev/proto/proto_busdma.c   (contents, props changed)
  head/sys/dev/proto/proto_busdma.h   (contents, props changed)
Modified:
  head/sys/dev/proto/proto.h
  head/sys/dev/proto/proto_bus_pci.c
  head/sys/dev/proto/proto_core.c
  head/sys/dev/proto/proto_dev.h

Modified: head/sys/dev/proto/proto.h
==============================================================================
--- head/sys/dev/proto/proto.h	Sat Jun  6 15:51:11 2015	(r284078)
+++ head/sys/dev/proto/proto.h	Sat Jun  6 16:09:25 2015	(r284079)
@@ -33,11 +33,15 @@
 
 #define	PROTO_RES_UNUSED	0
 #define	PROTO_RES_PCICFG	10
+#define	PROTO_RES_BUSDMA	11
 
 struct proto_res {
 	int		r_type;
 	int		r_rid;
-	struct resource *r_res;
+	union {
+		struct resource *res;
+		void *busdma;
+	} r_d;
 	u_long		r_size;
 	union {
 		void		*cookie;

Modified: head/sys/dev/proto/proto_bus_pci.c
==============================================================================
--- head/sys/dev/proto/proto_bus_pci.c	Sat Jun  6 15:51:11 2015	(r284078)
+++ head/sys/dev/proto/proto_bus_pci.c	Sat Jun  6 16:09:25 2015	(r284079)
@@ -87,6 +87,7 @@ proto_pci_attach(device_t dev)
 	sc = device_get_softc(dev);
 
 	proto_add_resource(sc, PROTO_RES_PCICFG, 0, NULL);
+	proto_add_resource(sc, PROTO_RES_BUSDMA, 0, NULL);
 
 	for (bar = 0; bar < PCIR_MAX_BAR_0; bar++) {
 		rid = PCIR_BAR(bar);

Added: head/sys/dev/proto/proto_busdma.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/proto/proto_busdma.c	Sat Jun  6 16:09:25 2015	(r284079)
@@ -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);
+}

Added: head/sys/dev/proto/proto_busdma.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/proto/proto_busdma.h	Sat Jun  6 16:09:25 2015	(r284079)
@@ -0,0 +1,50 @@
+/*-
+ * 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 _DEV_PROTO_BUSDMA_H_
+#define _DEV_PROTO_BUSDMA_H_
+
+struct proto_tag {
+	LIST_ENTRY(proto_tag)	link;
+	struct proto_tag	*parent;
+	bus_dma_tag_t		busdma_tag;
+};
+
+struct proto_busdma {
+	LIST_HEAD(,proto_tag)	tags;
+};
+
+struct proto_busdma *proto_busdma_attach(struct proto_softc *);
+int proto_busdma_detach(struct proto_softc *, struct proto_busdma *);
+
+int proto_busdma_cleanup(struct proto_softc *, struct proto_busdma *);
+
+int proto_busdma_ioctl(struct proto_softc *, struct proto_busdma *,
+    struct proto_ioc_busdma *);
+
+#endif /* _DEV_PROTO_BUSDMA_H_ */

Modified: head/sys/dev/proto/proto_core.c
==============================================================================
--- head/sys/dev/proto/proto_core.c	Sat Jun  6 15:51:11 2015	(r284078)
+++ head/sys/dev/proto/proto_core.c	Sat Jun  6 16:09:25 2015	(r284079)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/proto/proto.h>
 #include <dev/proto/proto_dev.h>
+#include <dev/proto/proto_busdma.h>
 
 CTASSERT(SYS_RES_IRQ != PROTO_RES_UNUSED &&
     SYS_RES_MEMORY != PROTO_RES_UNUSED &&
@@ -58,6 +59,9 @@ CTASSERT(SYS_RES_IRQ != PROTO_RES_UNUSED
 CTASSERT(SYS_RES_IRQ != PROTO_RES_PCICFG &&
     SYS_RES_MEMORY != PROTO_RES_PCICFG &&
     SYS_RES_IOPORT != PROTO_RES_PCICFG);
+CTASSERT(SYS_RES_IRQ != PROTO_RES_BUSDMA &&
+    SYS_RES_MEMORY != PROTO_RES_BUSDMA &&
+    SYS_RES_IOPORT != PROTO_RES_BUSDMA);
 
 devclass_t proto_devclass;
 char proto_driver_name[] = "proto";
@@ -97,7 +101,7 @@ proto_add_resource(struct proto_softc *s
 	r = sc->sc_res + sc->sc_rescnt++;
 	r->r_type = type;
 	r->r_rid = rid;
-	r->r_res = res;
+	r->r_d.res = res;
 	return (0);
 }
 
@@ -130,7 +134,7 @@ proto_attach(device_t dev)
 			break;
 		case SYS_RES_MEMORY:
 		case SYS_RES_IOPORT:
-			r->r_size = rman_get_size(r->r_res);
+			r->r_size = rman_get_size(r->r_d.res);
 			r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0666,
 			    "proto/%s/%02x.%s", device_get_desc(dev), r->r_rid,
 			    (r->r_type == SYS_RES_IOPORT) ? "io" : "mem");
@@ -144,6 +148,14 @@ proto_attach(device_t dev)
 			r->r_u.cdev->si_drv1 = sc;
 			r->r_u.cdev->si_drv2 = r;
 			break;
+		case PROTO_RES_BUSDMA:
+			r->r_d.busdma = proto_busdma_attach(sc);
+			r->r_size = 0;	/* no read(2) nor write(2) */
+			r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0666,
+			    "proto/%s/busdma", device_get_desc(dev));
+			r->r_u.cdev->si_drv1 = sc;
+			r->r_u.cdev->si_drv2 = r;
+			break;
 		}
 	}
 	return (0);
@@ -158,7 +170,7 @@ proto_detach(device_t dev)
 
 	sc = device_get_softc(dev);
 
-	/* Don't detach if we have open device filess. */
+	/* Don't detach if we have open device files. */
 	for (res = 0; res < sc->sc_rescnt; res++) {
 		r = sc->sc_res + res;
 		if (r->r_opened)
@@ -170,17 +182,22 @@ proto_detach(device_t dev)
 		switch (r->r_type) {
 		case SYS_RES_IRQ:
 			/* XXX TODO */
+			bus_release_resource(dev, r->r_type, r->r_rid,
+			    r->r_d.res);
 			break;
 		case SYS_RES_MEMORY:
 		case SYS_RES_IOPORT:
+			bus_release_resource(dev, r->r_type, r->r_rid,
+			    r->r_d.res);
+			destroy_dev(r->r_u.cdev);
+			break;
 		case PROTO_RES_PCICFG:
 			destroy_dev(r->r_u.cdev);
 			break;
-		}
-		if (r->r_res != NULL) {
-			bus_release_resource(dev, r->r_type, r->r_rid,
-			    r->r_res);
-			r->r_res = NULL;
+		case PROTO_RES_BUSDMA:
+			proto_busdma_detach(sc, r->r_d.busdma);
+			destroy_dev(r->r_u.cdev);
+			break;
 		}
 		r->r_type = PROTO_RES_UNUSED;
 	}
@@ -207,10 +224,14 @@ static int
 proto_close(struct cdev *cdev, int fflag, int devtype, struct thread *td)
 {
 	struct proto_res *r;
+	struct proto_softc *sc;
 
+	sc = cdev->si_drv1;
 	r = cdev->si_drv2;
 	if (!atomic_cmpset_acq_ptr(&r->r_opened, (uintptr_t)td->td_proc, 0UL))
 		return (ENXIO);
+	if (r->r_type == PROTO_RES_BUSDMA)
+		proto_busdma_cleanup(sc, r->r_d.busdma);
 	return (0);
 }
 
@@ -244,21 +265,21 @@ proto_read(struct cdev *cdev, struct uio
 	switch (width) {
 	case 1:
 		buf.x1[0] = (r->r_type == PROTO_RES_PCICFG) ?
-		    pci_read_config(dev, ofs, 1) : bus_read_1(r->r_res, ofs);
+		    pci_read_config(dev, ofs, 1) : bus_read_1(r->r_d.res, ofs);
 		break;
 	case 2:
 		buf.x2[0] = (r->r_type == PROTO_RES_PCICFG) ?
-		    pci_read_config(dev, ofs, 2) : bus_read_2(r->r_res, ofs);
+		    pci_read_config(dev, ofs, 2) : bus_read_2(r->r_d.res, ofs);
 		break;
 	case 4:
 		buf.x4[0] = (r->r_type == PROTO_RES_PCICFG) ?
-		    pci_read_config(dev, ofs, 4) : bus_read_4(r->r_res, ofs);
+		    pci_read_config(dev, ofs, 4) : bus_read_4(r->r_d.res, ofs);
 		break;
 #ifndef __i386__
 	case 8:
 		if (r->r_type == PROTO_RES_PCICFG)
 			return (EINVAL);
-		buf.x8[0] = bus_read_8(r->r_res, ofs);
+		buf.x8[0] = bus_read_8(r->r_d.res, ofs);
 		break;
 #endif
 	default:
@@ -305,25 +326,25 @@ proto_write(struct cdev *cdev, struct ui
 		if (r->r_type == PROTO_RES_PCICFG)
 			pci_write_config(dev, ofs, buf.x1[0], 1);
 		else
-			bus_write_1(r->r_res, ofs, buf.x1[0]);
+			bus_write_1(r->r_d.res, ofs, buf.x1[0]);
 		break;
 	case 2:
 		if (r->r_type == PROTO_RES_PCICFG)
 			pci_write_config(dev, ofs, buf.x2[0], 2);
 		else
-			bus_write_2(r->r_res, ofs, buf.x2[0]);
+			bus_write_2(r->r_d.res, ofs, buf.x2[0]);
 		break;
 	case 4:
 		if (r->r_type == PROTO_RES_PCICFG)
 			pci_write_config(dev, ofs, buf.x4[0], 4);
 		else
-			bus_write_4(r->r_res, ofs, buf.x4[0]);
+			bus_write_4(r->r_d.res, ofs, buf.x4[0]);
 		break;
 #ifndef __i386__
 	case 8:
 		if (r->r_type == PROTO_RES_PCICFG)
 			return (EINVAL);
-		bus_write_8(r->r_res, ofs, buf.x8[0]);
+		bus_write_8(r->r_d.res, ofs, buf.x8[0]);
 		break;
 #endif
 	default:
@@ -338,9 +359,12 @@ proto_ioctl(struct cdev *cdev, u_long cm
     struct thread *td)
 {
 	struct proto_ioc_region *region;
+	struct proto_ioc_busdma *busdma;
 	struct proto_res *r;
+	struct proto_softc *sc;
 	int error;
 
+	sc = cdev->si_drv1;
 	r = cdev->si_drv2;
 
 	error = 0;
@@ -351,7 +375,11 @@ proto_ioctl(struct cdev *cdev, u_long cm
 		if (r->r_type == PROTO_RES_PCICFG)
 			region->address = 0;
 		else
-			region->address = rman_get_start(r->r_res);
+			region->address = rman_get_start(r->r_d.res);
+		break;
+	case PROTO_IOC_BUSDMA:
+		busdma = (struct proto_ioc_busdma *)data;
+		error = proto_busdma_ioctl(sc, r->r_d.busdma, busdma);
 		break;
 	default:
 		error = ENOIOCTL;
@@ -376,7 +404,7 @@ proto_mmap(struct cdev *cdev, vm_ooffset
 		return (EACCES);
 	if (offset >= r->r_size)
 		return (EINVAL);
-	*paddr = rman_get_start(r->r_res) + offset;
+	*paddr = rman_get_start(r->r_d.res) + offset;
 #ifndef __sparc64__
 	*memattr = VM_MEMATTR_UNCACHEABLE;
 #endif

Modified: head/sys/dev/proto/proto_dev.h
==============================================================================
--- head/sys/dev/proto/proto_dev.h	Sat Jun  6 15:51:11 2015	(r284078)
+++ head/sys/dev/proto/proto_dev.h	Sat Jun  6 16:09:25 2015	(r284079)
@@ -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
@@ -40,4 +40,27 @@ struct proto_ioc_region {
 
 #define PROTO_IOC_REGION _IOWR(PROTO_IOC_CLASS, 1, struct proto_ioc_region)
 
+struct proto_ioc_busdma {
+	unsigned int	request;
+#define	PROTO_IOC_BUSDMA_TAG_CREATE	1
+#define	PROTO_IOC_BUSDMA_TAG_DERIVE	2
+#define	PROTO_IOC_BUSDMA_TAG_DESTROY	3
+	unsigned long	key;
+	union {
+		struct {
+			unsigned long	align;
+			unsigned long	bndry;
+			unsigned long	maxaddr;
+			unsigned long	maxsz;
+			unsigned long	maxsegsz;
+			unsigned int	nsegs;
+			unsigned int	datarate;
+			unsigned int	flags;
+		} tag;
+	} u;
+	unsigned long	result;
+};
+
+#define PROTO_IOC_BUSDMA _IOWR(PROTO_IOC_CLASS, 2, struct proto_ioc_busdma)
+
 #endif /* _DEV_PROTO_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506061609.t56G9P66021328>