This series re-factors the devfreq code a bit in preparation for the upcoming A6x related devfreq changes. The code applies cleanly on 4.17 and has been verified on DB820C.
V2: Addressed code review comments from Jordan Crouse.
Sharat Masetty (3): drm/msm: suspend devfreq on init drm/msm: move suspend/resume devfreq to their own functions drm/msm: re-factor devfreq code
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 16 +++++++++--- drivers/gpu/drm/msm/msm_gpu.c | 48 ++++++++++++++++++++++------------- drivers/gpu/drm/msm/msm_gpu.h | 6 ++++- 3 files changed, 48 insertions(+), 22 deletions(-)
-- 1.9.1
Devfreq turns on and starts recommending power level as soon as it is initialized. The GPU is still not powered on by the time the devfreq init happens and this leads to problems on GPU's where register access is needed to get/set power levels. So we start suspended and only restart devfreq when GPU is powered on.
Signed-off-by: Sharat Masetty smasetty@codeaurora.org --- drivers/gpu/drm/msm/msm_gpu.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 1c09acf..d7586f2 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -104,6 +104,8 @@ static void msm_devfreq_init(struct msm_gpu *gpu) dev_err(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n"); gpu->devfreq.devfreq = NULL; } + + devfreq_suspend_device(gpu->devfreq.devfreq); }
static int enable_pwrrail(struct msm_gpu *gpu)
This is needed for hardware revisions which do not rely on the generic suspend, resume handlers for power management.
Signed-off-by: Sharat Masetty smasetty@codeaurora.org --- drivers/gpu/drm/msm/msm_gpu.c | 23 +++++++++++++++-------- drivers/gpu/drm/msm/msm_gpu.h | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index d7586f2..c5d4627 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -203,6 +203,19 @@ static int disable_axi(struct msm_gpu *gpu) return 0; }
+void msm_gpu_resume_devfreq(struct msm_gpu *gpu) +{ + gpu->devfreq.busy_cycles = 0; + gpu->devfreq.time = ktime_get(); + + devfreq_resume_device(gpu->devfreq.devfreq); +} + +void msm_gpu_suspend_devfreq(struct msm_gpu *gpu) +{ + devfreq_suspend_device(gpu->devfreq.devfreq); +} + int msm_gpu_pm_resume(struct msm_gpu *gpu) { int ret; @@ -221,12 +234,7 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) if (ret) return ret;
- if (gpu->devfreq.devfreq) { - gpu->devfreq.busy_cycles = 0; - gpu->devfreq.time = ktime_get(); - - devfreq_resume_device(gpu->devfreq.devfreq); - } + msm_gpu_resume_devfreq(gpu);
gpu->needs_hw_init = true;
@@ -239,8 +247,7 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
DBG("%s", gpu->name);
- if (gpu->devfreq.devfreq) - devfreq_suspend_device(gpu->devfreq.devfreq); + msm_gpu_suspend_devfreq(gpu);
ret = disable_axi(gpu); if (ret) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index b824117..1876b81 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -226,6 +226,8 @@ static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
int msm_gpu_pm_suspend(struct msm_gpu *gpu); int msm_gpu_pm_resume(struct msm_gpu *gpu); +void msm_gpu_resume_devfreq(struct msm_gpu *gpu); +void msm_gpu_suspend_devfreq(struct msm_gpu *gpu);
int msm_gpu_hw_init(struct msm_gpu *gpu);
On Thu, May 31, 2018 at 12:52:03PM +0530, Sharat Masetty wrote:
This is needed for hardware revisions which do not rely on the generic suspend, resume handlers for power management.
Signed-off-by: Sharat Masetty smasetty@codeaurora.org
drivers/gpu/drm/msm/msm_gpu.c | 23 +++++++++++++++-------- drivers/gpu/drm/msm/msm_gpu.h | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index d7586f2..c5d4627 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -203,6 +203,19 @@ static int disable_axi(struct msm_gpu *gpu) return 0; }
+void msm_gpu_resume_devfreq(struct msm_gpu *gpu) +{
- gpu->devfreq.busy_cycles = 0;
- gpu->devfreq.time = ktime_get();
- devfreq_resume_device(gpu->devfreq.devfreq);
+}
I'm on the fence about this - it isn't strictly needed because it would be fine for the 6xx code to duplicate three lines of code but it does make it easier to update the statistics in one place. If others feel more strongly, chime in.
+void msm_gpu_suspend_devfreq(struct msm_gpu *gpu) +{
- devfreq_suspend_device(gpu->devfreq.devfreq);
+}
This on the other hand is entirely not needed. When 6xx does its thing it can just call devfreq_suspend_device directly. It is doubtful we will ever need anything more than this one line to stop devfreq.
int msm_gpu_pm_resume(struct msm_gpu *gpu) { int ret; @@ -221,12 +234,7 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) if (ret) return ret;
- if (gpu->devfreq.devfreq) {
gpu->devfreq.busy_cycles = 0;
gpu->devfreq.time = ktime_get();
devfreq_resume_device(gpu->devfreq.devfreq);
- }
msm_gpu_resume_devfreq(gpu);
gpu->needs_hw_init = true;
@@ -239,8 +247,7 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
DBG("%s", gpu->name);
- if (gpu->devfreq.devfreq)
devfreq_suspend_device(gpu->devfreq.devfreq);
msm_gpu_suspend_devfreq(gpu);
ret = disable_axi(gpu); if (ret)
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index b824117..1876b81 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -226,6 +226,8 @@ static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
int msm_gpu_pm_suspend(struct msm_gpu *gpu); int msm_gpu_pm_resume(struct msm_gpu *gpu); +void msm_gpu_resume_devfreq(struct msm_gpu *gpu); +void msm_gpu_suspend_devfreq(struct msm_gpu *gpu);
int msm_gpu_hw_init(struct msm_gpu *gpu);
-- 1.9.1
devfreq framework requires the drivers to provide busy time estimations. The GPU driver relies on the hardware performance counters for the busy time estimations, but different hardware revisions have counters which can be sourced from different clocks. So the busy time estimation will be target dependent. Additionally on targets where the clocks are completely controlled by the on chip microcontroller, fetching and setting the current GPU frequency will be different. This patch aims to embrace these differences by re-factoring the devfreq code a bit.
Signed-off-by: Sharat Masetty smasetty@codeaurora.org --- drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 16 ++++++++++++---- drivers/gpu/drm/msm/msm_gpu.c | 23 ++++++++++++++--------- drivers/gpu/drm/msm/msm_gpu.h | 4 +++- 3 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index d39400e..5cdf104 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -1219,12 +1219,20 @@ static struct msm_ringbuffer *a5xx_active_ring(struct msm_gpu *gpu) return a5xx_gpu->cur_ring; }
-static int a5xx_gpu_busy(struct msm_gpu *gpu, uint64_t *value) +static unsigned long a5xx_gpu_busy(struct msm_gpu *gpu) { - *value = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, - REG_A5XX_RBBM_PERFCTR_RBBM_0_HI); + u64 busy_cycles; + unsigned long busy_time;
- return 0; + busy_cycles = gpu_read64(gpu, REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, + REG_A5XX_RBBM_PERFCTR_RBBM_0_HI); + + busy_time = (busy_cycles - gpu->devfreq.busy_cycles) / + (clk_get_rate(gpu->core_clk) / 1000000); + + gpu->devfreq.busy_cycles = busy_cycles; + + return busy_time; }
static const struct adreno_gpu_funcs funcs = { diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index c5d4627..43e36d7 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -40,7 +40,11 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, if (IS_ERR(opp)) return PTR_ERR(opp);
- clk_set_rate(gpu->core_clk, *freq); + if (gpu->funcs->gpu_set_freq) + gpu->funcs->gpu_set_freq(gpu, *freq); + else + clk_set_rate(gpu->core_clk, *freq); + dev_pm_opp_put(opp);
return 0; @@ -50,16 +54,14 @@ static int msm_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *status) { struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev)); - u64 cycles; - u32 freq = ((u32) status->current_frequency) / 1000000; ktime_t time;
- status->current_frequency = (unsigned long) clk_get_rate(gpu->core_clk); - gpu->funcs->gpu_busy(gpu, &cycles); - - status->busy_time = ((u32) (cycles - gpu->devfreq.busy_cycles)) / freq; + if (gpu->funcs->gpu_get_freq) + status->current_frequency = gpu->funcs->gpu_get_freq(gpu); + else + status->current_frequency = clk_get_rate(gpu->core_clk);
- gpu->devfreq.busy_cycles = cycles; + status->busy_time = gpu->funcs->gpu_busy(gpu);
time = ktime_get(); status->total_time = ktime_us_delta(time, gpu->devfreq.time); @@ -72,7 +74,10 @@ static int msm_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) { struct msm_gpu *gpu = platform_get_drvdata(to_platform_device(dev));
- *freq = (unsigned long) clk_get_rate(gpu->core_clk); + if (gpu->funcs->gpu_get_freq) + *freq = gpu->funcs->gpu_get_freq(gpu); + else + *freq = clk_get_rate(gpu->core_clk);
return 0; } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 1876b81..000aae7 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -68,7 +68,9 @@ struct msm_gpu_funcs { /* for generation specific debugfs: */ int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor); #endif - int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value); + unsigned long (*gpu_busy)(struct msm_gpu *gpu); + unsigned long (*gpu_get_freq)(struct msm_gpu *gpu); + int (*gpu_set_freq)(struct msm_gpu *gpu, unsigned long freq); };
struct msm_gpu {
dri-devel@lists.freedesktop.org