diff options
Diffstat (limited to 'drivers/gpu/drm/lima/lima_sched.c')
| -rw-r--r-- | drivers/gpu/drm/lima/lima_sched.c | 41 | 
1 files changed, 36 insertions, 5 deletions
diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index eb46db0717cd..e6cefda00279 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -4,6 +4,7 @@  #include <linux/kthread.h>  #include <linux/slab.h>  #include <linux/vmalloc.h> +#include <linux/pm_runtime.h>  #include "lima_devfreq.h"  #include "lima_drv.h" @@ -194,13 +195,36 @@ static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job,  	return NULL;  } +static int lima_pm_busy(struct lima_device *ldev) +{ +	int ret; + +	/* resume GPU if it has been suspended by runtime PM */ +	ret = pm_runtime_get_sync(ldev->dev); +	if (ret < 0) +		return ret; + +	lima_devfreq_record_busy(&ldev->devfreq); +	return 0; +} + +static void lima_pm_idle(struct lima_device *ldev) +{ +	lima_devfreq_record_idle(&ldev->devfreq); + +	/* GPU can do auto runtime suspend */ +	pm_runtime_mark_last_busy(ldev->dev); +	pm_runtime_put_autosuspend(ldev->dev); +} +  static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)  {  	struct lima_sched_task *task = to_lima_task(job);  	struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); +	struct lima_device *ldev = pipe->ldev;  	struct lima_fence *fence;  	struct dma_fence *ret; -	int i; +	int i, err;  	/* after GPU reset */  	if (job->s_fence->finished.error < 0) @@ -209,6 +233,13 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)  	fence = lima_fence_create(pipe);  	if (!fence)  		return NULL; + +	err = lima_pm_busy(ldev); +	if (err < 0) { +		dma_fence_put(&fence->base); +		return NULL; +	} +  	task->fence = &fence->base;  	/* for caller usage of the fence, otherwise irq handler @@ -216,8 +247,6 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)  	 */  	ret = dma_fence_get(task->fence); -	lima_devfreq_record_busy(&pipe->ldev->devfreq); -  	pipe->current_task = task;  	/* this is needed for MMU to work correctly, otherwise GP/PP @@ -388,6 +417,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job)  {  	struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);  	struct lima_sched_task *task = to_lima_task(job); +	struct lima_device *ldev = pipe->ldev;  	if (!pipe->error)  		DRM_ERROR("lima job timeout\n"); @@ -413,7 +443,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job)  	pipe->current_vm = NULL;  	pipe->current_task = NULL; -	lima_devfreq_record_idle(&pipe->ldev->devfreq); +	lima_pm_idle(ldev);  	drm_sched_resubmit_jobs(&pipe->base);  	drm_sched_start(&pipe->base, true); @@ -485,6 +515,7 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)  void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)  {  	struct lima_sched_task *task = pipe->current_task; +	struct lima_device *ldev = pipe->ldev;  	if (pipe->error) {  		if (task && task->recoverable) @@ -495,6 +526,6 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)  		pipe->task_fini(pipe);  		dma_fence_signal(task->fence); -		lima_devfreq_record_idle(&pipe->ldev->devfreq); +		lima_pm_idle(ldev);  	}  }  | 
