aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-08-07 14:41:54 -0400
committerDave Airlie <airlied@redhat.com>2013-08-18 20:32:26 -0400
commitcabaafc78935521c5abc7ec72278dbaa5400c995 (patch)
treec5af38231d7484f421a6abfce09109a0b9d669c7
parentb17df86ece5e674c6f50b9a219067b9a80ea9dd1 (diff)
drm: add flip-work helper
A small helper to queue up work to do, from workqueue context, after a flip. Typically useful to defer unreffing buffers that may be read by the display controller until vblank. v1: original v2: wire up docbook + couple docbook fixes Signed-off-by: Rob Clark <robdclark@gmail.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--Documentation/DocBook/drm.tmpl6
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_flip_work.c124
-rw-r--r--include/drm/drm_flip_work.h76
4 files changed, 207 insertions, 1 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 9494ab8af9e7..f97d08ba59be 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2213,6 +2213,12 @@ void intel_crt_init(struct drm_device *dev)
2213!Edrivers/gpu/drm/drm_rect.c 2213!Edrivers/gpu/drm/drm_rect.c
2214 </sect2> 2214 </sect2>
2215 <sect2> 2215 <sect2>
2216 <title>Flip-work Helper Reference</title>
2217!Pinclude/drm/drm_flip_work.h flip utils
2218!Iinclude/drm/drm_flip_work.h
2219!Edrivers/gpu/drm/drm_flip_work.c
2220 </sect2>
2221 <sect2>
2216 <title>VMA Offset Manager</title> 2222 <title>VMA Offset Manager</title>
2217!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager 2223!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager
2218!Edrivers/gpu/drm/drm_vma_manager.c 2224!Edrivers/gpu/drm/drm_vma_manager.c
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d943b94afc90..2aaf082368a2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -13,7 +13,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
13 drm_crtc.o drm_modes.o drm_edid.o \ 13 drm_crtc.o drm_modes.o drm_edid.o \
14 drm_info.o drm_debugfs.o drm_encoder_slave.o \ 14 drm_info.o drm_debugfs.o drm_encoder_slave.o \
15 drm_trace_points.o drm_global.o drm_prime.o \ 15 drm_trace_points.o drm_global.o drm_prime.o \
16 drm_rect.o drm_vma_manager.o 16 drm_rect.o drm_vma_manager.o drm_flip_work.o
17 17
18drm-$(CONFIG_COMPAT) += drm_ioc32.o 18drm-$(CONFIG_COMPAT) += drm_ioc32.o
19drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o 19drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c
new file mode 100644
index 000000000000..e788882d9021
--- /dev/null
+++ b/drivers/gpu/drm/drm_flip_work.c
@@ -0,0 +1,124 @@
1/*
2 * Copyright (C) 2013 Red Hat
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "drmP.h"
25#include "drm_flip_work.h"
26
27/**
28 * drm_flip_work_queue - queue work
29 * @work: the flip-work
30 * @val: the value to queue
31 *
32 * Queues work, that will later be run (passed back to drm_flip_func_t
33 * func) on a work queue after drm_flip_work_commit() is called.
34 */
35void drm_flip_work_queue(struct drm_flip_work *work, void *val)
36{
37 if (kfifo_put(&work->fifo, (const void **)&val)) {
38 atomic_inc(&work->pending);
39 } else {
40 DRM_ERROR("%s fifo full!\n", work->name);
41 work->func(work, val);
42 }
43}
44EXPORT_SYMBOL(drm_flip_work_queue);
45
46/**
47 * drm_flip_work_commit - commit queued work
48 * @work: the flip-work
49 * @wq: the work-queue to run the queued work on
50 *
51 * Trigger work previously queued by drm_flip_work_queue() to run
52 * on a workqueue. The typical usage would be to queue work (via
53 * drm_flip_work_queue()) at any point (from vblank irq and/or
54 * prior), and then from vblank irq commit the queued work.
55 */
56void drm_flip_work_commit(struct drm_flip_work *work,
57 struct workqueue_struct *wq)
58{
59 uint32_t pending = atomic_read(&work->pending);
60 atomic_add(pending, &work->count);
61 atomic_sub(pending, &work->pending);
62 queue_work(wq, &work->worker);
63}
64EXPORT_SYMBOL(drm_flip_work_commit);
65
66static void flip_worker(struct work_struct *w)
67{
68 struct drm_flip_work *work = container_of(w, struct drm_flip_work, worker);
69 uint32_t count = atomic_read(&work->count);
70 void *val = NULL;
71
72 atomic_sub(count, &work->count);
73
74 while(count--)
75 if (!WARN_ON(!kfifo_get(&work->fifo, &val)))
76 work->func(work, val);
77}
78
79/**
80 * drm_flip_work_init - initialize flip-work
81 * @work: the flip-work to initialize
82 * @size: the max queue depth
83 * @name: debug name
84 * @func: the callback work function
85 *
86 * Initializes/allocates resources for the flip-work
87 *
88 * RETURNS:
89 * Zero on success, error code on failure.
90 */
91int drm_flip_work_init(struct drm_flip_work *work, int size,
92 const char *name, drm_flip_func_t func)
93{
94 int ret;
95
96 work->name = name;
97 atomic_set(&work->count, 0);
98 atomic_set(&work->pending, 0);
99 work->func = func;
100
101 ret = kfifo_alloc(&work->fifo, size, GFP_KERNEL);
102 if (ret) {
103 DRM_ERROR("could not allocate %s fifo\n", name);
104 return ret;
105 }
106
107 INIT_WORK(&work->worker, flip_worker);
108
109 return 0;
110}
111EXPORT_SYMBOL(drm_flip_work_init);
112
113/**
114 * drm_flip_work_cleanup - cleans up flip-work
115 * @work: the flip-work to cleanup
116 *
117 * Destroy resources allocated for the flip-work
118 */
119void drm_flip_work_cleanup(struct drm_flip_work *work)
120{
121 WARN_ON(!kfifo_is_empty(&work->fifo));
122 kfifo_free(&work->fifo);
123}
124EXPORT_SYMBOL(drm_flip_work_cleanup);
diff --git a/include/drm/drm_flip_work.h b/include/drm/drm_flip_work.h
new file mode 100644
index 000000000000..35c776ae7d3b
--- /dev/null
+++ b/include/drm/drm_flip_work.h
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2013 Red Hat
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#ifndef DRM_FLIP_WORK_H
25#define DRM_FLIP_WORK_H
26
27#include <linux/kfifo.h>
28#include <linux/workqueue.h>
29
30/**
31 * DOC: flip utils
32 *
33 * Util to queue up work to run from work-queue context after flip/vblank.
34 * Typically this can be used to defer unref of framebuffer's, cursor
35 * bo's, etc until after vblank. The APIs are all safe (and lockless)
36 * for up to one producer and once consumer at a time. The single-consumer
37 * aspect is ensured by committing the queued work to a single work-queue.
38 */
39
40struct drm_flip_work;
41
42/*
43 * drm_flip_func_t - callback function
44 *
45 * @work: the flip work
46 * @val: value queued via drm_flip_work_queue()
47 *
48 * Callback function to be called for each of the queue'd work items after
49 * drm_flip_work_commit() is called.
50 */
51typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val);
52
53/**
54 * struct drm_flip_work - flip work queue
55 * @name: debug name
56 * @pending: number of queued but not committed items
57 * @count: number of committed items
58 * @func: callback fxn called for each committed item
59 * @worker: worker which calls @func
60 */
61struct drm_flip_work {
62 const char *name;
63 atomic_t pending, count;
64 drm_flip_func_t func;
65 struct work_struct worker;
66 DECLARE_KFIFO_PTR(fifo, void *);
67};
68
69void drm_flip_work_queue(struct drm_flip_work *work, void *val);
70void drm_flip_work_commit(struct drm_flip_work *work,
71 struct workqueue_struct *wq);
72int drm_flip_work_init(struct drm_flip_work *work, int size,
73 const char *name, drm_flip_func_t func);
74void drm_flip_work_cleanup(struct drm_flip_work *work);
75
76#endif /* DRM_FLIP_WORK_H */