Author: marcel
Date: Thu Jul  4 02:51:34 2019
New Revision: 349714
URL: https://svnweb.freebsd.org/changeset/base/349714

Log:
  Lock busdma operations and serialize detach against open/close
  
  Use sx to allow M_WAITOK allocations (suggested by markj).
  
  admbugs: 782
  Reviewed by:  markj

Modified:
  head/sys/dev/proto/proto.h
  head/sys/dev/proto/proto_busdma.c
  head/sys/dev/proto/proto_busdma.h
  head/sys/dev/proto/proto_core.c

Modified: head/sys/dev/proto/proto.h
==============================================================================
--- head/sys/dev/proto/proto.h  Wed Jul  3 22:41:54 2019        (r349713)
+++ head/sys/dev/proto/proto.h  Thu Jul  4 02:51:34 2019        (r349714)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2014, 2015 Marcel Moolenaar
+ * Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,8 @@
 #define        PROTO_RES_BUSDMA        11
 
 struct proto_res {
-       int             r_type;
+       u_int           r_type:8;
+       u_int           r_opened:1;
        int             r_rid;
        union {
                struct resource *res;
@@ -47,13 +48,14 @@ struct proto_res {
                void            *cookie;
                struct cdev     *cdev;
        } r_u;
-       uintptr_t       r_opened;
 };
 
 struct proto_softc {
        device_t        sc_dev;
        struct proto_res sc_res[PROTO_RES_MAX];
        int             sc_rescnt;
+       int             sc_opencnt;
+       struct mtx      sc_mtx;
 };
 
 extern devclass_t proto_devclass;

Modified: head/sys/dev/proto/proto_busdma.c
==============================================================================
--- head/sys/dev/proto/proto_busdma.c   Wed Jul  3 22:41:54 2019        
(r349713)
+++ head/sys/dev/proto/proto_busdma.c   Thu Jul  4 02:51:34 2019        
(r349714)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2015 Marcel Moolenaar
+ * Copyright (c) 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 #include <sys/rman.h>
 #include <sys/sbuf.h>
+#include <sys/sx.h>
 #include <sys/uio.h>
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -355,6 +356,7 @@ proto_busdma_attach(struct proto_softc *sc)
        struct proto_busdma *busdma;
 
        busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
+       sx_init(&busdma->sxlck, "proto-busdma");
        return (busdma);
 }
 
@@ -363,6 +365,7 @@ proto_busdma_detach(struct proto_softc *sc, struct pro
 {
 
        proto_busdma_cleanup(sc, busdma);
+       sx_destroy(&busdma->sxlck);
        free(busdma, M_PROTO_BUSDMA);
        return (0);
 }
@@ -373,10 +376,12 @@ proto_busdma_cleanup(struct proto_softc *sc, struct pr
        struct proto_md *md, *md1;
        struct proto_tag *tag, *tag1;
 
+       sx_xlock(&busdma->sxlck);
        LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1)
                proto_busdma_md_destroy_internal(busdma, md);
        LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1)
                proto_busdma_tag_destroy(busdma, tag);
+       sx_xunlock(&busdma->sxlck);
        return (0);
 }
 
@@ -388,6 +393,8 @@ proto_busdma_ioctl(struct proto_softc *sc, struct prot
        struct proto_md *md;
        int error;
 
+       sx_xlock(&busdma->sxlck);
+
        error = 0;
        switch (ioc->request) {
        case PROTO_IOC_BUSDMA_TAG_CREATE:
@@ -470,6 +477,9 @@ proto_busdma_ioctl(struct proto_softc *sc, struct prot
                error = EINVAL;
                break;
        }
+
+       sx_xunlock(&busdma->sxlck);
+
        return (error);
 }
 
@@ -477,11 +487,20 @@ int
 proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr)
 {
        struct proto_md *md;
+       int result;
 
+       sx_xlock(&busdma->sxlck);
+
+       result = 0;
        LIST_FOREACH(md, &busdma->mds, mds) {
                if (physaddr >= trunc_page(md->physaddr) &&
-                   physaddr <= trunc_page(md->physaddr + md->tag->maxsz))
-                       return (1);
+                   physaddr <= trunc_page(md->physaddr + md->tag->maxsz)) {
+                       result = 1;
+                       break;
+               }
        }
-       return (0);
+
+       sx_xunlock(&busdma->sxlck);
+
+       return (result);
 }

Modified: head/sys/dev/proto/proto_busdma.h
==============================================================================
--- head/sys/dev/proto/proto_busdma.h   Wed Jul  3 22:41:54 2019        
(r349713)
+++ head/sys/dev/proto/proto_busdma.h   Thu Jul  4 02:51:34 2019        
(r349714)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2015 Marcel Moolenaar
+ * Copyright (c) 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -60,6 +60,7 @@ struct proto_busdma {
        LIST_HEAD(,proto_tag)   tags;
        LIST_HEAD(,proto_md)    mds;
        bus_dma_tag_t           bd_roottag;
+       struct sx               sxlck;
 };
 
 struct proto_busdma *proto_busdma_attach(struct proto_softc *);

Modified: head/sys/dev/proto/proto_core.c
==============================================================================
--- head/sys/dev/proto/proto_core.c     Wed Jul  3 22:41:54 2019        
(r349713)
+++ head/sys/dev/proto/proto_core.c     Thu Jul  4 02:51:34 2019        
(r349714)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2014, 2015 Marcel Moolenaar
+ * Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -184,6 +184,7 @@ proto_attach(device_t dev)
 
        sc = device_get_softc(dev);
        sc->sc_dev = dev;
+       mtx_init(&sc->sc_mtx, "proto-softc", NULL, MTX_DEF);
 
        for (res = 0; res < sc->sc_rescnt; res++) {
                r = sc->sc_res + res;
@@ -231,15 +232,16 @@ proto_detach(device_t dev)
 
        sc = device_get_softc(dev);
 
-       /* 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)
-                       return (EBUSY);
-       }
+       mtx_lock(&sc->sc_mtx);
+       if (sc->sc_opencnt == 0)
+               sc->sc_opencnt = -1;
+       mtx_unlock(&sc->sc_mtx);
+       if (sc->sc_opencnt > 0)
+               return (EBUSY);
 
        for (res = 0; res < sc->sc_rescnt; res++) {
                r = sc->sc_res + res;
+
                switch (r->r_type) {
                case SYS_RES_IRQ:
                        /* XXX TODO */
@@ -252,21 +254,25 @@ proto_detach(device_t dev)
                        break;
                case SYS_RES_MEMORY:
                case SYS_RES_IOPORT:
+                       destroy_dev(r->r_u.cdev);
                        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;
                case PROTO_RES_BUSDMA:
-                       proto_busdma_detach(sc, r->r_d.busdma);
                        destroy_dev(r->r_u.cdev);
+                       proto_busdma_detach(sc, r->r_d.busdma);
                        break;
                }
                r->r_type = PROTO_RES_UNUSED;
        }
+       mtx_lock(&sc->sc_mtx);
        sc->sc_rescnt = 0;
+       sc->sc_opencnt = 0;
+       mtx_unlock(&sc->sc_mtx);
+       mtx_destroy(&sc->sc_mtx);
        return (0);
 }
 
@@ -278,11 +284,23 @@ static int
 proto_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
 {
        struct proto_res *r;
+       struct proto_softc *sc;
+       int error;
 
-       r = cdev->si_drv2;
-       if (!atomic_cmpset_acq_ptr(&r->r_opened, 0UL, (uintptr_t)td->td_proc))
-               return (EBUSY);
-       return (0);
+       sc = cdev->si_drv1;
+       mtx_lock(&sc->sc_mtx);
+       if (sc->sc_opencnt >= 0) {
+               r = cdev->si_drv2;
+               if (!r->r_opened) {
+                       r->r_opened = 1;
+                       sc->sc_opencnt++;
+                       error = 0;
+               } else
+                       error = EBUSY;
+       } else
+               error = ENXIO;
+       mtx_unlock(&sc->sc_mtx);
+       return (error);
 }
 
 static int
@@ -290,14 +308,24 @@ proto_close(struct cdev *cdev, int fflag, int devtype,
 {
        struct proto_res *r;
        struct proto_softc *sc;
+       int error;
 
        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);
+       mtx_lock(&sc->sc_mtx);
+       if (sc->sc_opencnt > 0) {
+               r = cdev->si_drv2;
+               if (r->r_opened) {
+                       if (r->r_type == PROTO_RES_BUSDMA)
+                               proto_busdma_cleanup(sc, r->r_d.busdma);
+                       r->r_opened = 0;
+                       sc->sc_opencnt--;
+                       error = 0;
+               } else
+                       error = ENXIO;
+       } else
+               error = ENXIO;
+       mtx_unlock(&sc->sc_mtx);
+       return (error);
 }
 
 static int
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to