Commit 50de2e9e authored by Qiang Yu's avatar Qiang Yu

drm/lima: enable runtime pm

Enable runtime pm by default so GPU suspend when idle
for 200ms. This value can be changed by
autosuspend_delay_ms in device's power sysfs dir.

On Allwinner H3 lima_device_resume takes ~40us and
lima_device_suspend takes ~20us.
Tested-by: default avatarBhushan Shah <bshah@kde.org>
Reviewed-by: default avatarVasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: default avatarQiang Yu <yuq825@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200421133551.31481-11-yuq825@gmail.com
parent 63945d51
...@@ -404,6 +404,12 @@ static int lima_pdev_probe(struct platform_device *pdev) ...@@ -404,6 +404,12 @@ static int lima_pdev_probe(struct platform_device *pdev)
goto err_out2; goto err_out2;
} }
pm_runtime_set_active(ldev->dev);
pm_runtime_mark_last_busy(ldev->dev);
pm_runtime_set_autosuspend_delay(ldev->dev, 200);
pm_runtime_use_autosuspend(ldev->dev);
pm_runtime_enable(ldev->dev);
/* /*
* Register the DRM device with the core and the connectors with * Register the DRM device with the core and the connectors with
* sysfs. * sysfs.
...@@ -412,17 +418,16 @@ static int lima_pdev_probe(struct platform_device *pdev) ...@@ -412,17 +418,16 @@ static int lima_pdev_probe(struct platform_device *pdev)
if (err < 0) if (err < 0)
goto err_out3; goto err_out3;
platform_set_drvdata(pdev, ldev);
if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr)) if (sysfs_create_bin_file(&ldev->dev->kobj, &lima_error_state_attr))
dev_warn(ldev->dev, "fail to create error state sysfs\n"); dev_warn(ldev->dev, "fail to create error state sysfs\n");
return 0; return 0;
err_out3: err_out3:
lima_device_fini(ldev); pm_runtime_disable(ldev->dev);
err_out2:
lima_devfreq_fini(ldev); lima_devfreq_fini(ldev);
err_out2:
lima_device_fini(ldev);
err_out1: err_out1:
drm_dev_put(ddev); drm_dev_put(ddev);
err_out0: err_out0:
...@@ -436,10 +441,16 @@ static int lima_pdev_remove(struct platform_device *pdev) ...@@ -436,10 +441,16 @@ static int lima_pdev_remove(struct platform_device *pdev)
struct drm_device *ddev = ldev->ddev; struct drm_device *ddev = ldev->ddev;
sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr); sysfs_remove_bin_file(&ldev->dev->kobj, &lima_error_state_attr);
platform_set_drvdata(pdev, NULL);
drm_dev_unregister(ddev); drm_dev_unregister(ddev);
/* stop autosuspend to make sure device is in active state */
pm_runtime_set_autosuspend_delay(ldev->dev, -1);
pm_runtime_disable(ldev->dev);
lima_devfreq_fini(ldev); lima_devfreq_fini(ldev);
lima_device_fini(ldev); lima_device_fini(ldev);
drm_dev_put(ddev); drm_dev_put(ddev);
lima_sched_slab_fini(); lima_sched_slab_fini();
return 0; return 0;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include "lima_devfreq.h" #include "lima_devfreq.h"
#include "lima_drv.h" #include "lima_drv.h"
...@@ -194,13 +195,36 @@ static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job, ...@@ -194,13 +195,36 @@ static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job,
return NULL; 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) 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_task *task = to_lima_task(job);
struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); struct lima_sched_pipe *pipe = to_lima_pipe(job->sched);
struct lima_device *ldev = pipe->ldev;
struct lima_fence *fence; struct lima_fence *fence;
struct dma_fence *ret; struct dma_fence *ret;
int i; int i, err;
/* after GPU reset */ /* after GPU reset */
if (job->s_fence->finished.error < 0) if (job->s_fence->finished.error < 0)
...@@ -209,6 +233,13 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) ...@@ -209,6 +233,13 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
fence = lima_fence_create(pipe); fence = lima_fence_create(pipe);
if (!fence) if (!fence)
return NULL; return NULL;
err = lima_pm_busy(ldev);
if (err < 0) {
dma_fence_put(&fence->base);
return NULL;
}
task->fence = &fence->base; task->fence = &fence->base;
/* for caller usage of the fence, otherwise irq handler /* 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) ...@@ -216,8 +247,6 @@ static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job)
*/ */
ret = dma_fence_get(task->fence); ret = dma_fence_get(task->fence);
lima_devfreq_record_busy(&pipe->ldev->devfreq);
pipe->current_task = task; pipe->current_task = task;
/* this is needed for MMU to work correctly, otherwise GP/PP /* 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) ...@@ -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_pipe *pipe = to_lima_pipe(job->sched);
struct lima_sched_task *task = to_lima_task(job); struct lima_sched_task *task = to_lima_task(job);
struct lima_device *ldev = pipe->ldev;
if (!pipe->error) if (!pipe->error)
DRM_ERROR("lima job timeout\n"); DRM_ERROR("lima job timeout\n");
...@@ -413,7 +443,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job) ...@@ -413,7 +443,7 @@ static void lima_sched_timedout_job(struct drm_sched_job *job)
pipe->current_vm = NULL; pipe->current_vm = NULL;
pipe->current_task = NULL; pipe->current_task = NULL;
lima_devfreq_record_idle(&pipe->ldev->devfreq); lima_pm_idle(ldev);
drm_sched_resubmit_jobs(&pipe->base); drm_sched_resubmit_jobs(&pipe->base);
drm_sched_start(&pipe->base, true); drm_sched_start(&pipe->base, true);
...@@ -485,6 +515,7 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) ...@@ -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) void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
{ {
struct lima_sched_task *task = pipe->current_task; struct lima_sched_task *task = pipe->current_task;
struct lima_device *ldev = pipe->ldev;
if (pipe->error) { if (pipe->error) {
if (task && task->recoverable) if (task && task->recoverable)
...@@ -495,6 +526,6 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) ...@@ -495,6 +526,6 @@ void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
pipe->task_fini(pipe); pipe->task_fini(pipe);
dma_fence_signal(task->fence); dma_fence_signal(task->fence);
lima_devfreq_record_idle(&pipe->ldev->devfreq); lima_pm_idle(ldev);
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment