-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Rob Clark
authored and
Dave Airlie
committed
Aug 19, 2013
1 parent
b17df86
commit cabaafc
Showing
4 changed files
with
207 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/* | ||
* Copyright (C) 2013 Red Hat | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice (including the next | ||
* paragraph) shall be included in all copies or substantial portions of the | ||
* Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
|
||
#include "drmP.h" | ||
#include "drm_flip_work.h" | ||
|
||
/** | ||
* drm_flip_work_queue - queue work | ||
* @work: the flip-work | ||
* @val: the value to queue | ||
* | ||
* Queues work, that will later be run (passed back to drm_flip_func_t | ||
* func) on a work queue after drm_flip_work_commit() is called. | ||
*/ | ||
void drm_flip_work_queue(struct drm_flip_work *work, void *val) | ||
{ | ||
if (kfifo_put(&work->fifo, (const void **)&val)) { | ||
atomic_inc(&work->pending); | ||
} else { | ||
DRM_ERROR("%s fifo full!\n", work->name); | ||
work->func(work, val); | ||
} | ||
} | ||
EXPORT_SYMBOL(drm_flip_work_queue); | ||
|
||
/** | ||
* drm_flip_work_commit - commit queued work | ||
* @work: the flip-work | ||
* @wq: the work-queue to run the queued work on | ||
* | ||
* Trigger work previously queued by drm_flip_work_queue() to run | ||
* on a workqueue. The typical usage would be to queue work (via | ||
* drm_flip_work_queue()) at any point (from vblank irq and/or | ||
* prior), and then from vblank irq commit the queued work. | ||
*/ | ||
void drm_flip_work_commit(struct drm_flip_work *work, | ||
struct workqueue_struct *wq) | ||
{ | ||
uint32_t pending = atomic_read(&work->pending); | ||
atomic_add(pending, &work->count); | ||
atomic_sub(pending, &work->pending); | ||
queue_work(wq, &work->worker); | ||
} | ||
EXPORT_SYMBOL(drm_flip_work_commit); | ||
|
||
static void flip_worker(struct work_struct *w) | ||
{ | ||
struct drm_flip_work *work = container_of(w, struct drm_flip_work, worker); | ||
uint32_t count = atomic_read(&work->count); | ||
void *val = NULL; | ||
|
||
atomic_sub(count, &work->count); | ||
|
||
while(count--) | ||
if (!WARN_ON(!kfifo_get(&work->fifo, &val))) | ||
work->func(work, val); | ||
} | ||
|
||
/** | ||
* drm_flip_work_init - initialize flip-work | ||
* @work: the flip-work to initialize | ||
* @size: the max queue depth | ||
* @name: debug name | ||
* @func: the callback work function | ||
* | ||
* Initializes/allocates resources for the flip-work | ||
* | ||
* RETURNS: | ||
* Zero on success, error code on failure. | ||
*/ | ||
int drm_flip_work_init(struct drm_flip_work *work, int size, | ||
const char *name, drm_flip_func_t func) | ||
{ | ||
int ret; | ||
|
||
work->name = name; | ||
atomic_set(&work->count, 0); | ||
atomic_set(&work->pending, 0); | ||
work->func = func; | ||
|
||
ret = kfifo_alloc(&work->fifo, size, GFP_KERNEL); | ||
if (ret) { | ||
DRM_ERROR("could not allocate %s fifo\n", name); | ||
return ret; | ||
} | ||
|
||
INIT_WORK(&work->worker, flip_worker); | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL(drm_flip_work_init); | ||
|
||
/** | ||
* drm_flip_work_cleanup - cleans up flip-work | ||
* @work: the flip-work to cleanup | ||
* | ||
* Destroy resources allocated for the flip-work | ||
*/ | ||
void drm_flip_work_cleanup(struct drm_flip_work *work) | ||
{ | ||
WARN_ON(!kfifo_is_empty(&work->fifo)); | ||
kfifo_free(&work->fifo); | ||
} | ||
EXPORT_SYMBOL(drm_flip_work_cleanup); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright (C) 2013 Red Hat | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice (including the next | ||
* paragraph) shall be included in all copies or substantial portions of the | ||
* Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
*/ | ||
|
||
#ifndef DRM_FLIP_WORK_H | ||
#define DRM_FLIP_WORK_H | ||
|
||
#include <linux/kfifo.h> | ||
#include <linux/workqueue.h> | ||
|
||
/** | ||
* DOC: flip utils | ||
* | ||
* Util to queue up work to run from work-queue context after flip/vblank. | ||
* Typically this can be used to defer unref of framebuffer's, cursor | ||
* bo's, etc until after vblank. The APIs are all safe (and lockless) | ||
* for up to one producer and once consumer at a time. The single-consumer | ||
* aspect is ensured by committing the queued work to a single work-queue. | ||
*/ | ||
|
||
struct drm_flip_work; | ||
|
||
/* | ||
* drm_flip_func_t - callback function | ||
* | ||
* @work: the flip work | ||
* @val: value queued via drm_flip_work_queue() | ||
* | ||
* Callback function to be called for each of the queue'd work items after | ||
* drm_flip_work_commit() is called. | ||
*/ | ||
typedef void (*drm_flip_func_t)(struct drm_flip_work *work, void *val); | ||
|
||
/** | ||
* struct drm_flip_work - flip work queue | ||
* @name: debug name | ||
* @pending: number of queued but not committed items | ||
* @count: number of committed items | ||
* @func: callback fxn called for each committed item | ||
* @worker: worker which calls @func | ||
*/ | ||
struct drm_flip_work { | ||
const char *name; | ||
atomic_t pending, count; | ||
drm_flip_func_t func; | ||
struct work_struct worker; | ||
DECLARE_KFIFO_PTR(fifo, void *); | ||
}; | ||
|
||
void drm_flip_work_queue(struct drm_flip_work *work, void *val); | ||
void drm_flip_work_commit(struct drm_flip_work *work, | ||
struct workqueue_struct *wq); | ||
int drm_flip_work_init(struct drm_flip_work *work, int size, | ||
const char *name, drm_flip_func_t func); | ||
void drm_flip_work_cleanup(struct drm_flip_work *work); | ||
|
||
#endif /* DRM_FLIP_WORK_H */ |