summaryrefslogtreecommitdiffstats
path: root/sys/alpha
diff options
context:
space:
mode:
Diffstat (limited to 'sys/alpha')
-rw-r--r--sys/alpha/alpha/busdma_machdep.c61
-rw-r--r--sys/alpha/include/bus.h19
-rw-r--r--sys/alpha/isa/isa_dma.c4
3 files changed, 77 insertions, 7 deletions
diff --git a/sys/alpha/alpha/busdma_machdep.c b/sys/alpha/alpha/busdma_machdep.c
index 7e50116..4df7bd2 100644
--- a/sys/alpha/alpha/busdma_machdep.c
+++ b/sys/alpha/alpha/busdma_machdep.c
@@ -64,6 +64,8 @@ struct bus_dma_tag {
int flags;
int ref_count;
int map_count;
+ bus_dma_lock_t *lockfunc;
+ void *lockfuncarg;
};
struct bounce_page {
@@ -94,7 +96,6 @@ struct bus_dmamap {
vm_offset_t busaddress; /* address in bus space */
bus_dmamap_callback_t *callback;
void *callback_arg;
- struct mtx *callback_mtx;
void *sgmaphandle; /* handle into sgmap */
STAILQ_ENTRY(bus_dmamap) links;
};
@@ -129,6 +130,46 @@ run_filter(bus_dma_tag_t dmat, bus_addr_t paddr)
return (retval);
}
+/*
+ * Convenience function for manipulating driver locks from busdma (during
+ * busdma_swi, for example). Drivers that don't provide their own locks
+ * should specify &Giant to dmat->lockfuncarg. Drivers that use their own
+ * non-mutex locking scheme don't have to use this at all.
+ */
+void
+busdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
+{
+ struct mtx *dmtx;
+
+ dmtx = (struct mtx *)arg;
+ switch (op) {
+ case BUS_DMA_LOCK:
+ mtx_lock(dmtx);
+ break;
+ case BUS_DMA_UNLOCK:
+ mtx_unlock(dmtx);
+ break;
+ default:
+ panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
+ }
+}
+
+/*
+ * dflt_lock should never get called. It gets put into the dma tag when
+ * lockfunc == NULL, which is only valid if the maps that are associated
+ * with the tag are meant to never be defered.
+ * XXX Should have a way to identify which driver is responsible here.
+ */
+static void
+dflt_lock(void *arg, bus_dma_lock_op_t op)
+{
+#ifdef INVARIANTS
+ panic("driver error: busdma dflt_lock called");
+#else
+ printf("DRIVER_ERROR: busdma dflt_lock called\n");
+#endif
+}
+
#define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4
/*
* Allocate a device specific dma_tag.
@@ -138,7 +179,8 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
bus_size_t boundary, bus_addr_t lowaddr,
bus_addr_t highaddr, bus_dma_filter_t *filter,
void *filterarg, bus_size_t maxsize, int nsegments,
- bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat)
+ bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+ void *lockfuncarg, bus_dma_tag_t *dmat)
{
bus_dma_tag_t newtag;
int error = 0;
@@ -163,6 +205,13 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
newtag->flags = flags;
newtag->ref_count = 1; /* Count ourself */
newtag->map_count = 0;
+ if (lockfunc != NULL) {
+ newtag->lockfunc = lockfunc;
+ newtag->lockfuncarg = lockfuncarg;
+ } else {
+ newtag->lockfunc = dflt_lock;
+ newtag->lockfuncarg = NULL;
+ }
/* Take into account any restrictions imposed by our parent tag */
if (parent != NULL) {
@@ -926,18 +975,18 @@ free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
void
busdma_swi(void)
{
+ bus_dma_tag_t dmat;
struct bus_dmamap *map;
mtx_lock(&bounce_lock);
while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) {
STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links);
mtx_unlock(&bounce_lock);
- if (map->callback_mtx != NULL)
- mtx_lock(map->callback_mtx);
+ dmat = map->dmat;
+ (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK);
bus_dmamap_load(map->dmat, map, map->buf, map->buflen,
map->callback, map->callback_arg, /*flags*/0);
- if (map->callback_mtx != NULL)
- mtx_unlock(map->callback_mtx);
+ (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK);
mtx_lock(&bounce_lock);
}
mtx_unlock(&bounce_lock);
diff --git a/sys/alpha/include/bus.h b/sys/alpha/include/bus.h
index 76f6477..582484c 100644
--- a/sys/alpha/include/bus.h
+++ b/sys/alpha/include/bus.h
@@ -523,6 +523,17 @@ typedef struct bus_dma_segment {
typedef int bus_dma_filter_t(void *, bus_addr_t);
/*
+ * A function that performs driver-specific syncronization on behalf of
+ * busdma.
+ */
+typedef enum {
+ BUS_DMA_LOCK = 0x01,
+ BUS_DMA_UNLOCK = 0x02,
+} bus_dma_lock_op_t;
+
+typedef void bus_dma_lock_t(void *, bus_dma_lock_op_t);
+
+/*
* Allocate a device specific dma_tag encapsulating the constraints of
* the parent tag in addition to other restrictions specified:
*
@@ -547,7 +558,8 @@ int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignemnt,
bus_size_t boundary, bus_addr_t lowaddr,
bus_addr_t highaddr, bus_dma_filter_t *filtfunc,
void *filtfuncarg, bus_size_t maxsize, int nsegments,
- bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat);
+ bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+ void *lockfuncarg, bus_dma_tag_t *dmat);
int bus_dma_tag_destroy(bus_dma_tag_t dmat);
@@ -629,4 +641,9 @@ void _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map);
if ((dmamap) != NULL) \
_bus_dmamap_unload(dmat, dmamap)
+/*
+ * Generic helper function for manipulating mutexes.
+ */
+void busdma_lock_mutex(void *arg, bus_dma_lock_op_t op);
+
#endif /* _ALPHA_BUS_H_ */
diff --git a/sys/alpha/isa/isa_dma.c b/sys/alpha/isa/isa_dma.c
index ef671be..22eea8a 100644
--- a/sys/alpha/isa/isa_dma.c
+++ b/sys/alpha/isa/isa_dma.c
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/bus.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@@ -131,6 +133,8 @@ isa_dmainit(chan, bouncebufsize)
/*maxsize*/bouncebufsize,
/*nsegments*/1, /*maxsegz*/0x3ffff,
/*flags*/BUS_DMA_ISA,
+ /*lockfunc*/busdma_lock_mutex,
+ /*lockarg*/&Giant,
&dma_tag[chan]) != 0) {
panic("isa_dmainit: unable to create dma tag\n");
}
OpenPOWER on IntegriCloud