From: Jordan Crouse <jcrouse@codeaurora.org>
To: Rob Clark <robdclark@gmail.com>
Cc: dri-devel@lists.freedesktop.org, linux-arm-msm@vger.kernel.org
Subject: Re: [PATCH 4/7] drm/msm: crank down gpu when inactive
Date: Mon, 10 Mar 2014 14:24:13 -0600 [thread overview]
Message-ID: <531E1F6D.6020308@codeaurora.org> (raw)
In-Reply-To: <1394470062-27442-5-git-send-email-robdclark@gmail.com>
On 03/10/2014 10:47 AM, Rob Clark wrote:
> Shut down the clks when the gpu has nothing to do. A short inactivity
> timer is used to provide a low pass filter for power transitions.
Good luck. Power management will take years off your life.
> Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: Jordan Crouse <jcrouse@codeaurora.org>
> ---
> drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 10 +++++
> drivers/gpu/drm/msm/msm_drv.c | 7 ++-
> drivers/gpu/drm/msm/msm_gpu.c | 85 +++++++++++++++++++++++++++++++++--
> drivers/gpu/drm/msm/msm_gpu.h | 16 ++++++-
> 4 files changed, 113 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
> index 59ed762..e6cb2bc 100644
> --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
> @@ -395,9 +395,15 @@ static const unsigned int a3xx_registers[] = {
> #ifdef CONFIG_DEBUG_FS
> static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
> {
> + struct drm_device *dev = gpu->dev;
> int i;
>
> adreno_show(gpu, m);
> +
> + mutex_lock(&dev->struct_mutex);
> +
> + gpu->funcs->pm_resume(gpu);
> +
> seq_printf(m, "status: %08x\n",
> gpu_read(gpu, REG_A3XX_RBBM_STATUS));
>
> @@ -413,6 +419,10 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
> seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
> }
> }
> +
> + gpu->funcs->pm_suspend(gpu);
> +
> + mutex_unlock(&dev->struct_mutex);
> }
> #endif
>
> diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
> index e6adafc..e913efa 100644
> --- a/drivers/gpu/drm/msm/msm_drv.c
> +++ b/drivers/gpu/drm/msm/msm_drv.c
> @@ -311,7 +311,6 @@ static void load_gpu(struct drm_device *dev)
> gpu = NULL;
> /* not fatal */
> }
> - mutex_unlock(&dev->struct_mutex);
>
> if (gpu) {
> int ret;
> @@ -321,10 +320,16 @@ static void load_gpu(struct drm_device *dev)
> dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
> gpu->funcs->destroy(gpu);
> gpu = NULL;
> + } else {
> + /* give inactive pm a chance to kick in: */
> + msm_gpu_retire(gpu);
> }
> +
> }
>
> priv->gpu = gpu;
> +
> + mutex_unlock(&dev->struct_mutex);
> }
>
> static int msm_open(struct drm_device *dev, struct drm_file *file)
> diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
> index 0cfe3f4..3e667ca 100644
> --- a/drivers/gpu/drm/msm/msm_gpu.c
> +++ b/drivers/gpu/drm/msm/msm_gpu.c
> @@ -154,9 +154,18 @@ static int disable_axi(struct msm_gpu *gpu)
>
> int msm_gpu_pm_resume(struct msm_gpu *gpu)
> {
> + struct drm_device *dev = gpu->dev;
> int ret;
>
> - DBG("%s", gpu->name);
> + DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);
> +
> + WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> + if (gpu->active_cnt++ > 0)
> + return 0;
> +
> + if (WARN_ON(gpu->active_cnt <= 0))
> + return -EINVAL;
>
> ret = enable_pwrrail(gpu);
> if (ret)
> @@ -175,9 +184,18 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
>
> int msm_gpu_pm_suspend(struct msm_gpu *gpu)
> {
> + struct drm_device *dev = gpu->dev;
> int ret;
>
> - DBG("%s", gpu->name);
> + DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);
> +
> + WARN_ON(!mutex_is_locked(&dev->struct_mutex));
> +
> + if (--gpu->active_cnt > 0)
> + return 0;
> +
> + if (WARN_ON(gpu->active_cnt < 0))
> + return -EINVAL;
>
> ret = disable_axi(gpu);
> if (ret)
> @@ -195,6 +213,55 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
> }
>
> /*
> + * Inactivity detection (for suspend):
> + */
> +
> +static void inactive_worker(struct work_struct *work)
> +{
> + struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work);
> + struct drm_device *dev = gpu->dev;
> +
> + if (gpu->inactive)
> + return;
> +
> + DBG("%s: inactive!\n", gpu->name);
> + mutex_lock(&dev->struct_mutex);
> + if (!(msm_gpu_active(gpu) || gpu->inactive)) {
> + disable_axi(gpu);
> + disable_clk(gpu);
> + gpu->inactive = true;
> + }
> + mutex_unlock(&dev->struct_mutex);
> +}
> +
> +static void inactive_handler(unsigned long data)
> +{
> + struct msm_gpu *gpu = (struct msm_gpu *)data;
> + struct msm_drm_private *priv = gpu->dev->dev_private;
> +
> + queue_work(priv->wq, &gpu->inactive_work);
> +}
> +
> +/* cancel inactive timer and make sure we are awake: */
> +static void inactive_cancel(struct msm_gpu *gpu)
> +{
> + DBG("%s", gpu->name);
> + del_timer(&gpu->inactive_timer);
> + if (gpu->inactive) {
> + enable_clk(gpu);
> + enable_axi(gpu);
> + gpu->inactive = false;
> + }
> +}
> +
> +static void inactive_start(struct msm_gpu *gpu)
> +{
> + DBG("%s", gpu->name);
> + mod_timer(&gpu->inactive_timer,
> + round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES));
> +}
> +
> +/*
> * Hangcheck detection for locked gpu:
> */
>
> @@ -206,7 +273,10 @@ static void recover_worker(struct work_struct *work)
> dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name);
>
> mutex_lock(&dev->struct_mutex);
> - gpu->funcs->recover(gpu);
> + if (msm_gpu_active(gpu)) {
> + inactive_cancel(gpu);
> + gpu->funcs->recover(gpu);
> + }
> mutex_unlock(&dev->struct_mutex);
>
> msm_gpu_retire(gpu);
> @@ -281,6 +351,9 @@ static void retire_worker(struct work_struct *work)
> }
>
> mutex_unlock(&dev->struct_mutex);
> +
> + if (!msm_gpu_active(gpu))
> + inactive_start(gpu);
> }
>
> /* call from irq handler to schedule work to retire bo's */
> @@ -302,6 +375,8 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
>
> gpu->submitted_fence = submit->fence;
>
> + inactive_cancel(gpu);
> +
> ret = gpu->funcs->submit(gpu, submit, ctx);
> priv->lastctx = ctx;
>
> @@ -357,11 +432,15 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
> gpu->dev = drm;
> gpu->funcs = funcs;
> gpu->name = name;
> + gpu->inactive = true;
>
> INIT_LIST_HEAD(&gpu->active_list);
> INIT_WORK(&gpu->retire_work, retire_worker);
> + INIT_WORK(&gpu->inactive_work, inactive_worker);
> INIT_WORK(&gpu->recover_work, recover_worker);
>
> + setup_timer(&gpu->inactive_timer, inactive_handler,
> + (unsigned long)gpu);
> setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
> (unsigned long)gpu);
>
> diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
> index 458db8c..fad2700 100644
> --- a/drivers/gpu/drm/msm/msm_gpu.h
> +++ b/drivers/gpu/drm/msm/msm_gpu.h
> @@ -72,6 +72,10 @@ struct msm_gpu {
>
> uint32_t submitted_fence;
>
> + /* is gpu powered/active? */
> + int active_cnt;
> + bool inactive;
> +
> /* worker for handling active-list retiring: */
> struct work_struct retire_work;
>
> @@ -91,7 +95,12 @@ struct msm_gpu {
> uint32_t bsc;
> #endif
>
> - /* Hang Detction: */
> + /* Hang and Inactivity Detection:
> + */
> +#define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */
> +#define DRM_MSM_INACTIVE_JIFFIES msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD)
> + struct timer_list inactive_timer;
> + struct work_struct inactive_work;
> #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
> #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD)
> struct timer_list hangcheck_timer;
> @@ -99,6 +108,11 @@ struct msm_gpu {
> struct work_struct recover_work;
> };
>
> +static inline bool msm_gpu_active(struct msm_gpu *gpu)
> +{
> + return gpu->submitted_fence > gpu->funcs->last_fence(gpu);
> +}
> +
> static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)
> {
> msm_writel(data, gpu->mmio + (reg << 2));
>
--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
next prev parent reply other threads:[~2014-03-10 20:24 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-10 16:47 [PATCH 0/7] drm/msm: what's in store for 3.15 Rob Clark
2014-03-10 16:47 ` [PATCH 1/7] drm/msm: hdmi audio support Rob Clark
2014-03-10 16:47 ` [PATCH 2/7] drm/msm: add hang_debug module param Rob Clark
2014-03-10 20:17 ` Jordan Crouse
2014-03-10 20:27 ` Rob Clark
2014-03-10 16:47 ` [PATCH 3/7] drm/msm: spin helper Rob Clark
2014-03-10 20:27 ` Jordan Crouse
2014-03-10 16:47 ` [PATCH 4/7] drm/msm: crank down gpu when inactive Rob Clark
2014-03-10 20:24 ` Jordan Crouse [this message]
2014-03-10 20:39 ` Rob Clark
2014-03-10 16:47 ` [PATCH 5/7] drm/msm: add chip-id param Rob Clark
2014-03-10 20:20 ` Jordan Crouse
2014-03-10 16:47 ` [PATCH 6/7] drm/msm: use componentised device support Rob Clark
2014-03-10 16:47 ` [PATCH 7/7] drm/msm: validate flags, etc Rob Clark
2014-03-10 20:22 ` Jordan Crouse
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=531E1F6D.6020308@codeaurora.org \
--to=jcrouse@codeaurora.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=robdclark@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox