diff options
Diffstat (limited to 'drivers/gpu/drm/drm_writeback.c')
| -rw-r--r-- | drivers/gpu/drm/drm_writeback.c | 102 |
1 files changed, 84 insertions, 18 deletions
diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index c20e6fe00cb3..43d9e3bb3a94 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c @@ -9,12 +9,14 @@ * of such GNU licence. */ +#include <linux/dma-fence.h> + #include <drm/drm_crtc.h> +#include <drm/drm_device.h> +#include <drm/drm_drv.h> #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_property.h> #include <drm/drm_writeback.h> -#include <drm/drmP.h> -#include <linux/dma-fence.h> /** * DOC: overview @@ -239,14 +241,52 @@ fail: } EXPORT_SYMBOL(drm_writeback_connector_init); +int drm_writeback_set_fb(struct drm_connector_state *conn_state, + struct drm_framebuffer *fb) +{ + WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK); + + if (!conn_state->writeback_job) { + conn_state->writeback_job = + kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL); + if (!conn_state->writeback_job) + return -ENOMEM; + + conn_state->writeback_job->connector = + drm_connector_to_writeback(conn_state->connector); + } + + drm_framebuffer_assign(&conn_state->writeback_job->fb, fb); + return 0; +} + +int drm_writeback_prepare_job(struct drm_writeback_job *job) +{ + struct drm_writeback_connector *connector = job->connector; + const struct drm_connector_helper_funcs *funcs = + connector->base.helper_private; + int ret; + + if (funcs->prepare_writeback_job) { + ret = funcs->prepare_writeback_job(connector, job); + if (ret < 0) + return ret; + } + + job->prepared = true; + return 0; +} +EXPORT_SYMBOL(drm_writeback_prepare_job); + /** * drm_writeback_queue_job - Queue a writeback job for later signalling * @wb_connector: The writeback connector to queue a job on - * @job: The job to queue + * @conn_state: The connector state containing the job to queue * - * This function adds a job to the job_queue for a writeback connector. It - * should be considered to take ownership of the writeback job, and so any other - * references to the job must be cleared after calling this function. + * This function adds the job contained in @conn_state to the job_queue for a + * writeback connector. It takes ownership of the writeback job and sets the + * @conn_state->writeback_job to NULL, and so no access to the job may be + * performed by the caller after this function returns. * * Drivers must ensure that for a given writeback connector, jobs are queued in * exactly the same order as they will be completed by the hardware (and @@ -258,16 +298,39 @@ EXPORT_SYMBOL(drm_writeback_connector_init); * See also: drm_writeback_signal_completion() */ void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, - struct drm_writeback_job *job) + struct drm_connector_state *conn_state) { + struct drm_writeback_job *job; unsigned long flags; + job = conn_state->writeback_job; + conn_state->writeback_job = NULL; + spin_lock_irqsave(&wb_connector->job_lock, flags); list_add_tail(&job->list_entry, &wb_connector->job_queue); spin_unlock_irqrestore(&wb_connector->job_lock, flags); } EXPORT_SYMBOL(drm_writeback_queue_job); +void drm_writeback_cleanup_job(struct drm_writeback_job *job) +{ + struct drm_writeback_connector *connector = job->connector; + const struct drm_connector_helper_funcs *funcs = + connector->base.helper_private; + + if (job->prepared && funcs->cleanup_writeback_job) + funcs->cleanup_writeback_job(connector, job); + + if (job->fb) + drm_framebuffer_put(job->fb); + + if (job->out_fence) + dma_fence_put(job->out_fence); + + kfree(job); +} +EXPORT_SYMBOL(drm_writeback_cleanup_job); + /* * @cleanup_work: deferred cleanup of a writeback job * @@ -280,10 +343,9 @@ static void cleanup_work(struct work_struct *work) struct drm_writeback_job *job = container_of(work, struct drm_writeback_job, cleanup_work); - drm_framebuffer_put(job->fb); - kfree(job); -} + drm_writeback_cleanup_job(job); +} /** * drm_writeback_signal_completion - Signal the completion of a writeback job @@ -307,25 +369,29 @@ drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector, { unsigned long flags; struct drm_writeback_job *job; + struct dma_fence *out_fence; spin_lock_irqsave(&wb_connector->job_lock, flags); job = list_first_entry_or_null(&wb_connector->job_queue, struct drm_writeback_job, list_entry); - if (job) { + if (job) list_del(&job->list_entry); - if (job->out_fence) { - if (status) - dma_fence_set_error(job->out_fence, status); - dma_fence_signal(job->out_fence); - dma_fence_put(job->out_fence); - } - } + spin_unlock_irqrestore(&wb_connector->job_lock, flags); if (WARN_ON(!job)) return; + out_fence = job->out_fence; + if (out_fence) { + if (status) + dma_fence_set_error(out_fence, status); + dma_fence_signal(out_fence); + dma_fence_put(out_fence); + job->out_fence = NULL; + } + INIT_WORK(&job->cleanup_work, cleanup_work); queue_work(system_long_wq, &job->cleanup_work); } |
