Linux ARM-MSM sub-architecture
 help / color / mirror / Atom feed
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

  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