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: Bhushan Shah <bshah@kde.org> Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com> Signed-off-by: Qiang Yu <yuq825@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200421133551.31481-11-yuq825@gmail.com
This commit is contained in:
Родитель
63945d5149
Коммит
50de2e9ebb
|
@ -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)
|
||||||
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)
|
||||||
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 @@
|
||||||
#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,
|
||||||
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)
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче