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_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to