Message ID | 1538646103-27445-5-git-send-email-smasetty@codeaurora.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | msm/drm: a6xx DCVS series | expand |
On Thu, Oct 04, 2018 at 03:11:43PM +0530, Sharat Masetty wrote: > Implement routines to estimate GPU busy time and fetching the > current frequency for the polling interval. This is required by > the devfreq framework which recommends a frequency change if needed. > The driver code then tries to set this new frequency on the GPU by > sending an Out Of Band(OOB) request to the GMU. > > Signed-off-by: Sharat Masetty <smasetty@codeaurora.org> > --- > drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 38 +++++++++++++++++++++++++++++++---- > drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 2 ++ > drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 27 +++++++++++++++++++++++++ > drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 3 ++- > 4 files changed, 65 insertions(+), 5 deletions(-) > > diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > index 613d639..5b65873 100644 > --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c > @@ -61,7 +61,7 @@ static bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu) > A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF)); > } > > -static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) > +static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) > { > gmu_write(gmu, REG_A6XX_GMU_DCVS_ACK_OPTION, 0); > > @@ -78,7 +78,37 @@ static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) > a6xx_gmu_set_oob(gmu, GMU_OOB_DCVS_SET); > a6xx_gmu_clear_oob(gmu, GMU_OOB_DCVS_SET); > > - return gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN); > + ret = gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN); > + if (ret) > + dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret); > + > + gmu->freq = gmu->gpu_freqs[index]; > +} > + > +void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq) > +{ > + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); > + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); > + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; > + u32 perf_index = 0; > + > + if (freq == gmu->freq) > + return; > + > + for (perf_index = 0; perf_index < gmu->nr_gpu_freqs - 1; perf_index++) > + if (freq == gmu->gpu_freqs[perf_index]) > + break; > + > + __a6xx_gmu_set_freq(gmu, perf_index); > +} > + > +unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu) > +{ > + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); > + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); > + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; > + > + return gmu->freq; > } > > static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu) > @@ -637,7 +667,7 @@ int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu) > ret = a6xx_hfi_start(gmu, GMU_COLD_BOOT); > > /* Set the GPU back to the highest power frequency */ > - a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); > + __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); > > out: > if (ret) > @@ -676,7 +706,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) > ret = a6xx_hfi_start(gmu, status); > > /* Set the GPU to the highest power frequency */ > - a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); > + __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); > > out: > /* Make sure to turn off the boot OOB request on error */ > diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h > index f34630c..35f765a 100644 > --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h > +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h > @@ -74,6 +74,8 @@ struct a6xx_gmu { > unsigned long gmu_freqs[4]; > u32 cx_arc_votes[4]; > > + unsigned long freq; > + > struct a6xx_hfi_queue queues[2]; > > struct tasklet_struct hfi_tasklet; > diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > index 5f36b8d..e4ac95f 100644 > --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c > @@ -7,6 +7,8 @@ > #include "a6xx_gpu.h" > #include "a6xx_gmu.xml.h" > > +#include <linux/devfreq.h> > + > static inline bool _a6xx_check_idle(struct msm_gpu *gpu) > { > struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); > @@ -682,6 +684,8 @@ static int a6xx_pm_resume(struct msm_gpu *gpu) > > gpu->needs_hw_init = true; > > + msm_gpu_resume_devfreq(gpu); > + > return ret; > } > > @@ -690,6 +694,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) > struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); > struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); > > + devfreq_suspend_device(gpu->devfreq.devfreq); > + > /* > * Make sure the GMU is idle before continuing (because some transitions > * may use VBIF > @@ -753,6 +759,24 @@ static void a6xx_destroy(struct msm_gpu *gpu) > kfree(a6xx_gpu); > } > > +static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu) > +{ > + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); > + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); > + u64 busy_cycles; > + unsigned long busy_time; > + > + busy_cycles = gmu_read64(&a6xx_gpu->gmu, > + REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, > + REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H); > + > + busy_time = ((busy_cycles - gpu->devfreq.busy_cycles) * 10) / 192; I'm not sure if this will anger the compiler. You might need to use do_div instead. I guess we'll see if anybody complains. > + gpu->devfreq.busy_cycles = busy_cycles; > + > + return busy_time; > +} > + > static const struct adreno_gpu_funcs funcs = { > .base = { > .get_param = adreno_get_param, > @@ -768,6 +792,9 @@ static void a6xx_destroy(struct msm_gpu *gpu) > #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) > .show = a6xx_show, > #endif > + .gpu_busy = a6xx_gpu_busy, > + .gpu_get_freq = a6xx_gmu_get_freq, > + .gpu_set_freq = a6xx_gmu_set_freq, > }, > .get_timestamp = a6xx_get_timestamp, > }; > diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h > index dd69e5b..4127dce 100644 > --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h > +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h > @@ -56,5 +56,6 @@ struct a6xx_gpu { > > int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node); > void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu); > - Nit - this was an unnecessary line change. > +void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq); > +unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu); > #endif /* __A6XX_GPU_H__ */ > -- > 1.9.1 >
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 613d639..5b65873 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -61,7 +61,7 @@ static bool a6xx_gmu_gx_is_on(struct a6xx_gmu *gmu) A6XX_GMU_SPTPRAC_PWR_CLK_STATUS_GX_HM_CLK_OFF)); } -static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) +static void __a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) { gmu_write(gmu, REG_A6XX_GMU_DCVS_ACK_OPTION, 0); @@ -78,7 +78,37 @@ static int a6xx_gmu_set_freq(struct a6xx_gmu *gmu, int index) a6xx_gmu_set_oob(gmu, GMU_OOB_DCVS_SET); a6xx_gmu_clear_oob(gmu, GMU_OOB_DCVS_SET); - return gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN); + ret = gmu_read(gmu, REG_A6XX_GMU_DCVS_RETURN); + if (ret) + dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret); + + gmu->freq = gmu->gpu_freqs[index]; +} + +void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + u32 perf_index = 0; + + if (freq == gmu->freq) + return; + + for (perf_index = 0; perf_index < gmu->nr_gpu_freqs - 1; perf_index++) + if (freq == gmu->gpu_freqs[perf_index]) + break; + + __a6xx_gmu_set_freq(gmu, perf_index); +} + +unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + + return gmu->freq; } static bool a6xx_gmu_check_idle_level(struct a6xx_gmu *gmu) @@ -637,7 +667,7 @@ int a6xx_gmu_reset(struct a6xx_gpu *a6xx_gpu) ret = a6xx_hfi_start(gmu, GMU_COLD_BOOT); /* Set the GPU back to the highest power frequency */ - a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); + __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); out: if (ret) @@ -676,7 +706,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) ret = a6xx_hfi_start(gmu, status); /* Set the GPU to the highest power frequency */ - a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); + __a6xx_gmu_set_freq(gmu, gmu->nr_gpu_freqs - 1); out: /* Make sure to turn off the boot OOB request on error */ diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h index f34630c..35f765a 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.h @@ -74,6 +74,8 @@ struct a6xx_gmu { unsigned long gmu_freqs[4]; u32 cx_arc_votes[4]; + unsigned long freq; + struct a6xx_hfi_queue queues[2]; struct tasklet_struct hfi_tasklet; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 5f36b8d..e4ac95f 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -7,6 +7,8 @@ #include "a6xx_gpu.h" #include "a6xx_gmu.xml.h" +#include <linux/devfreq.h> + static inline bool _a6xx_check_idle(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -682,6 +684,8 @@ static int a6xx_pm_resume(struct msm_gpu *gpu) gpu->needs_hw_init = true; + msm_gpu_resume_devfreq(gpu); + return ret; } @@ -690,6 +694,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + devfreq_suspend_device(gpu->devfreq.devfreq); + /* * Make sure the GMU is idle before continuing (because some transitions * may use VBIF @@ -753,6 +759,24 @@ static void a6xx_destroy(struct msm_gpu *gpu) kfree(a6xx_gpu); } +static unsigned long a6xx_gpu_busy(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + u64 busy_cycles; + unsigned long busy_time; + + busy_cycles = gmu_read64(&a6xx_gpu->gmu, + REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_L, + REG_A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_0_H); + + busy_time = ((busy_cycles - gpu->devfreq.busy_cycles) * 10) / 192; + + gpu->devfreq.busy_cycles = busy_cycles; + + return busy_time; +} + static const struct adreno_gpu_funcs funcs = { .base = { .get_param = adreno_get_param, @@ -768,6 +792,9 @@ static void a6xx_destroy(struct msm_gpu *gpu) #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) .show = a6xx_show, #endif + .gpu_busy = a6xx_gpu_busy, + .gpu_get_freq = a6xx_gmu_get_freq, + .gpu_set_freq = a6xx_gmu_set_freq, }, .get_timestamp = a6xx_get_timestamp, }; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index dd69e5b..4127dce 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -56,5 +56,6 @@ struct a6xx_gpu { int a6xx_gmu_probe(struct a6xx_gpu *a6xx_gpu, struct device_node *node); void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu); - +void a6xx_gmu_set_freq(struct msm_gpu *gpu, unsigned long freq); +unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu); #endif /* __A6XX_GPU_H__ */
Implement routines to estimate GPU busy time and fetching the current frequency for the polling interval. This is required by the devfreq framework which recommends a frequency change if needed. The driver code then tries to set this new frequency on the GPU by sending an Out Of Band(OOB) request to the GMU. Signed-off-by: Sharat Masetty <smasetty@codeaurora.org> --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 38 +++++++++++++++++++++++++++++++---- drivers/gpu/drm/msm/adreno/a6xx_gmu.h | 2 ++ drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 27 +++++++++++++++++++++++++ drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 3 ++- 4 files changed, 65 insertions(+), 5 deletions(-)