summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2003-07-01 15:52:06 +0000
committerscottl <scottl@FreeBSD.org>2003-07-01 15:52:06 +0000
commit4d495abb9d6f6e6d703264c4133ce1f0c4e7df92 (patch)
tree1bbd76935b6d5917753df7328c69bd2f3c75f15a /sys/powerpc
parent40bbdc533036dcf851a5b4c44f1b64b82b887a5a (diff)
downloadFreeBSD-src-4d495abb9d6f6e6d703264c4133ce1f0c4e7df92.zip
FreeBSD-src-4d495abb9d6f6e6d703264c4133ce1f0c4e7df92.tar.gz
Mega busdma API commit.
Add two new arguments to bus_dma_tag_create(): lockfunc and lockfuncarg. Lockfunc allows a driver to provide a function for managing its locking semantics while using busdma. At the moment, this is used for the asynchronous busdma_swi and callback mechanism. Two lockfunc implementations are provided: busdma_lock_mutex() performs standard mutex operations on the mutex that is specified from lockfuncarg. dftl_lock() is a panic implementation and is defaulted to when NULL, NULL are passed to bus_dma_tag_create(). The only time that NULL, NULL should ever be used is when the driver ensures that bus_dmamap_load() will not be deferred. Drivers that do not provide their own locking can pass busdma_lock_mutex,&Giant args in order to preserve the former behaviour. sparc64 and powerpc do not provide real busdma_swi functions, so this is largely a noop on those platforms. The busdma_swi on is64 is not properly locked yet, so warnings will be emitted on this platform when busdma callback deferrals happen. If anyone gets panics or warnings from dflt_lock() being called, please let me know right away. Reviewed by: tmm, gibbs
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/include/bus.h18
-rw-r--r--sys/powerpc/powerpc/busdma_machdep.c53
2 files changed, 68 insertions, 3 deletions
diff --git a/sys/powerpc/include/bus.h b/sys/powerpc/include/bus.h
index eff6e8f..3ee2de5 100644
--- a/sys/powerpc/include/bus.h
+++ b/sys/powerpc/include/bus.h
@@ -797,6 +797,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:
*
@@ -820,7 +831,8 @@ int 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 *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);
@@ -896,4 +908,8 @@ void bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t);
*/
void bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map);
+/*
+ * Generic helper function for manipulating mutexes.
+ */
+void busdma_lock_mutex(void *arg, bus_dma_lock_op_t op);
#endif /* _MACPPC_BUS_H_ */
diff --git a/sys/powerpc/powerpc/busdma_machdep.c b/sys/powerpc/powerpc/busdma_machdep.c
index 3d6d402..f3ef3e3 100644
--- a/sys/powerpc/powerpc/busdma_machdep.c
+++ b/sys/powerpc/powerpc/busdma_machdep.c
@@ -67,6 +67,8 @@ struct bus_dma_tag {
int flags;
int ref_count;
int map_count;
+ bus_dma_lock_t *lockfunc;
+ void *lockfuncarg;
};
struct bus_dmamap {
@@ -75,10 +77,49 @@ struct bus_dmamap {
bus_size_t buflen; /* unmapped buffer length */
bus_dmamap_callback_t *callback;
void *callback_arg;
- struct mtx *callback_mtx;
};
/*
+ * 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
+}
+
+/*
* Allocate a device specific dma_tag.
*/
int
@@ -86,7 +127,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;
@@ -111,6 +153,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
OpenPOWER on IntegriCloud