drm/msm/devfreq: Add 1ms delay before clamping freq

Add a short delay before clamping to idle frequency on active->idle
transition.  It takes ~0.5ms to increase the freq again on the next
idle->active transition, so this helps avoid extra freq transitions
on workloads that bounce between CPU and GPU.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Link: https://lore.kernel.org/r/20210927230455.1066297-2-robdclark@gmail.com
Signed-off-by: Rob Clark <robdclark@chromium.org>
This commit is contained in:
Rob Clark 2021-09-27 16:04:54 -07:00
parent ddb6e37a50
commit 658f4c8296
2 changed files with 37 additions and 8 deletions

View file

@ -112,6 +112,13 @@ struct msm_gpu_devfreq {
* it is inactive.
*/
unsigned long idle_freq;
/**
* idle_work:
*
* Used to delay clamping to idle freq on active->idle transition.
*/
struct msm_hrtimer_work idle_work;
};
struct msm_gpu {

View file

@ -88,8 +88,12 @@ static struct devfreq_dev_profile msm_devfreq_profile = {
.get_cur_freq = msm_devfreq_get_cur_freq,
};
static void msm_devfreq_idle_work(struct kthread_work *work);
void msm_devfreq_init(struct msm_gpu *gpu)
{
struct msm_gpu_devfreq *df = &gpu->devfreq;
/* We need target support to do devfreq */
if (!gpu->funcs->gpu_busy)
return;
@ -105,25 +109,27 @@ void msm_devfreq_init(struct msm_gpu *gpu)
msm_devfreq_profile.freq_table = NULL;
msm_devfreq_profile.max_state = 0;
gpu->devfreq.devfreq = devm_devfreq_add_device(&gpu->pdev->dev,
df->devfreq = devm_devfreq_add_device(&gpu->pdev->dev,
&msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND,
NULL);
if (IS_ERR(gpu->devfreq.devfreq)) {
if (IS_ERR(df->devfreq)) {
DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
gpu->devfreq.devfreq = NULL;
df->devfreq = NULL;
return;
}
devfreq_suspend_device(gpu->devfreq.devfreq);
devfreq_suspend_device(df->devfreq);
gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node,
gpu->devfreq.devfreq);
gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node, df->devfreq);
if (IS_ERR(gpu->cooling)) {
DRM_DEV_ERROR(&gpu->pdev->dev,
"Couldn't register GPU cooling device\n");
gpu->cooling = NULL;
}
msm_hrtimer_work_init(&df->idle_work, gpu->worker, msm_devfreq_idle_work,
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
}
void msm_devfreq_cleanup(struct msm_gpu *gpu)
@ -154,6 +160,11 @@ void msm_devfreq_active(struct msm_gpu *gpu)
if (!df->devfreq)
return;
/*
* Cancel any pending transition to idle frequency:
*/
hrtimer_cancel(&df->idle_work.timer);
/*
* Hold devfreq lock to synchronize with get_dev_status()/
* target() callbacks
@ -184,9 +195,12 @@ void msm_devfreq_active(struct msm_gpu *gpu)
mutex_unlock(&df->devfreq->lock);
}
void msm_devfreq_idle(struct msm_gpu *gpu)
static void msm_devfreq_idle_work(struct kthread_work *work)
{
struct msm_gpu_devfreq *df = &gpu->devfreq;
struct msm_gpu_devfreq *df = container_of(work,
struct msm_gpu_devfreq, idle_work.work);
struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq);
unsigned long idle_freq, target_freq = 0;
if (!df->devfreq)
@ -207,3 +221,11 @@ void msm_devfreq_idle(struct msm_gpu *gpu)
mutex_unlock(&df->devfreq->lock);
}
void msm_devfreq_idle(struct msm_gpu *gpu)
{
struct msm_gpu_devfreq *df = &gpu->devfreq;
msm_hrtimer_queue_work(&df->idle_work, ms_to_ktime(1),
HRTIMER_MODE_ABS);
}