Partially restore the handling of the GPU load history. Accumulate the busy_time and and total_time measured in active state during the polling period. This results in slightly smoother picture of the GPU frequencies (measured on the a530/msm8996, using kmscube in different resolutions). A call to msm_devfreq_get_dev_status() from msm_devfreq_active() was removed in 69f06a5d854f ("drm/msm: remove explicit devfreq status reset"), because dev_pm_qos_update_request() triggered that internally. As the commit fadcc3ab1302 ("drm/msm/gpu: Bypass PM QoS constraint for idle clamp") removed the calls to dev_pm_qos_update_request(), this removal was also reverted. The code doesn't take the frequency into account while accumulating the data to keep the code simple for the RFC. Cc: Chia-I Wu <olvaffe@xxxxxxxxx> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> --- drivers/gpu/drm/msm/msm_gpu.h | 3 +++ drivers/gpu/drm/msm/msm_gpu_devfreq.c | 30 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index fc1c0d8611a8..9d1783375dcc 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -156,6 +156,9 @@ struct msm_gpu_devfreq { /** suspended: tracks if we're suspended */ bool suspended; + + /* stats for the current period */ + struct devfreq_dev_status status; }; struct msm_gpu { diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index e27dbf12b5e8..92cb022c8628 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -74,7 +74,7 @@ static unsigned long get_freq(struct msm_gpu *gpu) return clk_get_rate(gpu->core_clk); } -static int msm_devfreq_get_dev_status(struct device *dev, +static int msm_devfreq_get_dev_status_int(struct device *dev, struct devfreq_dev_status *status) { struct msm_gpu *gpu = dev_to_gpu(dev); @@ -112,6 +112,22 @@ static int msm_devfreq_get_dev_status(struct device *dev, return 0; } +static int msm_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *status) +{ + struct msm_gpu *gpu = dev_to_gpu(dev); + struct msm_gpu_devfreq *df = &gpu->devfreq; + + msm_devfreq_get_dev_status_int(&gpu->pdev->dev, status); + status->busy_time += df->status.busy_time; + status->total_time += df->status.total_time; + + df->status.busy_time = 0; + df->status.total_time = 0; + + return 0; +} + static int msm_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) { *freq = get_freq(dev_to_gpu(dev)); @@ -290,6 +306,7 @@ void msm_devfreq_active(struct msm_gpu *gpu) struct msm_gpu_devfreq *df = &gpu->devfreq; unsigned int idle_time; unsigned long target_freq; + struct devfreq_dev_status status; if (!has_devfreq(gpu)) return; @@ -319,6 +336,12 @@ void msm_devfreq_active(struct msm_gpu *gpu) if (target_freq) msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); + /* + * Reset the polling interval so we aren't inconsistent + * about freq vs busy/total cycles + */ + msm_devfreq_get_dev_status_int(&gpu->pdev->dev, &status); + mutex_unlock(&df->devfreq->lock); /* @@ -339,6 +362,7 @@ static void msm_devfreq_idle_work(struct kthread_work *work) struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq); struct msm_drm_private *priv = gpu->dev->dev_private; unsigned long idle_freq, target_freq = 0; + struct devfreq_dev_status status; /* * Hold devfreq lock to synchronize with get_dev_status()/ @@ -346,6 +370,10 @@ static void msm_devfreq_idle_work(struct kthread_work *work) */ mutex_lock(&df->devfreq->lock); + msm_devfreq_get_dev_status_int(&gpu->pdev->dev, &status); + df->status.busy_time += status.busy_time; + df->status.total_time += status.total_time; + idle_freq = get_freq(gpu); if (priv->gpu_clamp_to_idle) -- 2.30.2