diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-05-11 17:14:00 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2019-05-11 17:14:00 +0000 |
commit | 74a3930c42e5a66668964e2a200db77c24f7f762 (patch) | |
tree | 1101f6ca4c5e102a9f2e61608a9ddfd853169171 | |
parent | 947db4f1e8c683924984260d2c05639f7f975a79 (diff) |
implement dma_fence_array
-rw-r--r-- | sys/dev/pci/drm/drm_linux.c | 107 | ||||
-rw-r--r-- | sys/dev/pci/drm/include/linux/dma-fence-array.h | 31 |
2 files changed, 123 insertions, 15 deletions
diff --git a/sys/dev/pci/drm/drm_linux.c b/sys/dev/pci/drm/drm_linux.c index 88e4b9265b0..60c9889451f 100644 --- a/sys/dev/pci/drm/drm_linux.c +++ b/sys/dev/pci/drm/drm_linux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: drm_linux.c,v 1.35 2019/05/10 18:35:00 kettenis Exp $ */ +/* $OpenBSD: drm_linux.c,v 1.36 2019/05/11 17:13:59 jsg Exp $ */ /* * Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org> * Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org> @@ -26,6 +26,7 @@ #include <linux/mod_devicetable.h> #include <linux/acpi.h> #include <linux/pagevec.h> +#include <linux/dma-fence-array.h> void tasklet_run(void *arg) @@ -903,6 +904,110 @@ dma_fence_context_alloc(unsigned int num) return __sync_add_and_fetch(&drm_fence_count, num) - num; } +static const char * +dma_fence_array_get_driver_name(struct dma_fence *fence) +{ + return "dma_fence_array"; +} + +static const char * +dma_fence_array_get_timeline_name(struct dma_fence *fence) +{ + return "unbound"; +} + +static void +irq_dma_fence_array_work(struct irq_work *wrk) +{ + struct dma_fence_array *dfa = container_of(wrk, typeof(*dfa), work); + + dma_fence_signal(&dfa->base); + dma_fence_put(&dfa->base); +} + +static void +dma_fence_array_cb_func(struct dma_fence *f, struct dma_fence_cb *cb) +{ + struct dma_fence_array_cb *array_cb = + container_of(cb, struct dma_fence_array_cb, cb); + struct dma_fence_array *dfa = array_cb->array; + + if (atomic_dec_and_test(&dfa->num_pending)) + irq_work_queue(&dfa->work); + else + dma_fence_put(&dfa->base); +} + +static bool +dma_fence_array_enable_signaling(struct dma_fence *fence) +{ + struct dma_fence_array *dfa = to_dma_fence_array(fence); + struct dma_fence_array_cb *cb = (void *)(&dfa[1]); + int i; + + for (i = 0; i < dfa->num_fences; ++i) { + cb[i].array = dfa; + dma_fence_get(&dfa->base); + if (dma_fence_add_callback(dfa->fences[i], &cb[i].cb, + dma_fence_array_cb_func)) { + dma_fence_put(&dfa->base); + if (atomic_dec_and_test(&dfa->num_pending)) + return false; + } + } + + return true; +} + +static bool dma_fence_array_signaled(struct dma_fence *fence) +{ + struct dma_fence_array *dfa = to_dma_fence_array(fence); + + return atomic_read(&dfa->num_pending) <= 0; +} + +static void dma_fence_array_release(struct dma_fence *fence) +{ + struct dma_fence_array *dfa = to_dma_fence_array(fence); + int i; + + for (i = 0; i < dfa->num_fences; ++i) + dma_fence_put(dfa->fences[i]); + + free(dfa->fences, M_DRM, 0); + dma_fence_free(fence); +} + +struct dma_fence_array * +dma_fence_array_create(int num_fences, struct dma_fence **fences, u64 context, + unsigned seqno, bool signal_on_any) +{ + struct dma_fence_array *dfa = malloc(sizeof(*dfa) + + (num_fences * sizeof(struct dma_fence_array_cb)), + M_DRM, M_WAITOK|M_CANFAIL|M_ZERO); + if (dfa == NULL) + return NULL; + + mtx_init(&dfa->lock, IPL_TTY); + dma_fence_init(&dfa->base, &dma_fence_array_ops, &dfa->lock, + context, seqno); + init_irq_work(&dfa->work, irq_dma_fence_array_work); + + dfa->num_fences = num_fences; + atomic_set(&dfa->num_pending, signal_on_any ? 1 : num_fences); + dfa->fences = fences; + + return dfa; +} + +const struct dma_fence_ops dma_fence_array_ops = { + .get_driver_name = dma_fence_array_get_driver_name, + .get_timeline_name = dma_fence_array_get_timeline_name, + .enable_signaling = dma_fence_array_enable_signaling, + .signaled = dma_fence_array_signaled, + .release = dma_fence_array_release, +}; + int dmabuf_read(struct file *fp, struct uio *uio, int fflags) { diff --git a/sys/dev/pci/drm/include/linux/dma-fence-array.h b/sys/dev/pci/drm/include/linux/dma-fence-array.h index da49d7cf7cc..7af8044c2d7 100644 --- a/sys/dev/pci/drm/include/linux/dma-fence-array.h +++ b/sys/dev/pci/drm/include/linux/dma-fence-array.h @@ -4,37 +4,40 @@ #define _LINUX_DMA_FENCE_ARRAY_H #include <linux/dma-fence.h> +#include <linux/irq_work.h> -#ifndef STUB -#include <sys/types.h> -#include <sys/systm.h> -#define STUB() do { printf("%s: stub\n", __func__); } while(0) -#endif +struct dma_fence_array_cb { + struct dma_fence_cb cb; + struct dma_fence_array *array; +}; struct dma_fence_array { struct dma_fence base; unsigned int num_fences; struct dma_fence **fences; + struct mutex lock; + struct irq_work work; + int num_pending; }; +extern const struct dma_fence_ops dma_fence_array_ops; + static inline struct dma_fence_array * to_dma_fence_array(struct dma_fence *fence) { - return NULL; + if (fence->ops != &dma_fence_array_ops) + return NULL; + + return container_of(fence, struct dma_fence_array, base); } static inline bool dma_fence_is_array(struct dma_fence *fence) { - return false; + return fence->ops == &dma_fence_array_ops; } -static inline struct dma_fence_array * -dma_fence_array_create(int num_fences, struct dma_fence **fences, u64 context, - unsigned seqno, bool signal_on_any) -{ - STUB(); - return NULL; -} +struct dma_fence_array *dma_fence_array_create(int, struct dma_fence **, + u64, unsigned, bool); #endif |