On Thu, May 03, 2012 at 12:35:20PM +0100, Chris Wilson wrote:
> Whilst marking the device as active is protect by struct_mutex, we would
> mark the individual components as not-busy without any locking, leading
> to potential confusion and missed powersaving (or even performance
> loss). Move the softirq accesses to an atomic and defer the actual
> update until we acquire the struct_mutex in the worker.
> 
> Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>

I'm still confused about the locking, i.e. I think dev_priv->busy and
dev_priv->idle deserve small comments to explain what they're for. The
other thing is that the gpu_idle_timer reinvents our perfectly useable
delayed request retiring code (and in doing so is rather racy). I think we
should kill that and update the gpu busy/idleness in retire_work_handler.
That way the gpu would only be marked idle when it truely is.
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_dma.c      |    2 +-
>  drivers/gpu/drm/i915/i915_drv.h      |    3 +-
>  drivers/gpu/drm/i915/intel_display.c |   86 
> +++++++++++++++-------------------
>  drivers/gpu/drm/i915/intel_drv.h     |    1 -
>  4 files changed, 42 insertions(+), 50 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index ee25584..ee402c5 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1701,7 +1701,7 @@ bool i915_gpu_busy(void)
>               goto out_unlock;
>       dev_priv = i915_mch_dev;
>  
> -     ret = dev_priv->busy;
> +     ret = !!(dev_priv->busy & (1 << 31));
>  
>  out_unlock:
>       spin_unlock(&mchdev_lock);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 3815d9a..47e5722 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -778,7 +778,8 @@ typedef struct drm_i915_private {
>       int lvds_downclock;
>       struct work_struct idle_work;
>       struct timer_list idle_timer;
> -     bool busy;
> +     unsigned busy;
> +     atomic_t idle;
>       u16 orig_clock;
>       int child_dev_num;
>       struct child_device_config *child_dev;
> diff --git a/drivers/gpu/drm/i915/intel_display.c 
> b/drivers/gpu/drm/i915/intel_display.c
> index d5aa2d2..1428e6e 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -5519,14 +5519,7 @@ static void intel_gpu_idle_timer(unsigned long arg)
>       struct drm_device *dev = (struct drm_device *)arg;
>       drm_i915_private_t *dev_priv = dev->dev_private;
>  
> -     if (!list_empty(&dev_priv->mm.active_list)) {
> -             /* Still processing requests, so just re-arm the timer. */
> -             mod_timer(&dev_priv->idle_timer, jiffies +
> -                       msecs_to_jiffies(GPU_IDLE_TIMEOUT));
> -             return;
> -     }
> -
> -     dev_priv->busy = false;
> +     atomic_set_mask(1 << 31, &dev_priv->idle);
>       queue_work(dev_priv->wq, &dev_priv->idle_work);
>  }
>  
> @@ -5535,19 +5528,9 @@ static void intel_gpu_idle_timer(unsigned long arg)
>  static void intel_crtc_idle_timer(unsigned long arg)
>  {
>       struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
> -     struct drm_crtc *crtc = &intel_crtc->base;
> -     drm_i915_private_t *dev_priv = crtc->dev->dev_private;
> -     struct intel_framebuffer *intel_fb;
> +     drm_i915_private_t *dev_priv = intel_crtc->base.dev->dev_private;
>  
> -     intel_fb = to_intel_framebuffer(crtc->fb);
> -     if (intel_fb && intel_fb->obj->active) {
> -             /* The framebuffer is still being accessed by the GPU. */
> -             mod_timer(&intel_crtc->idle_timer, jiffies +
> -                       msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
> -             return;
> -     }
> -
> -     intel_crtc->busy = false;
> +     atomic_set_mask(1 << intel_crtc->pipe, &dev_priv->idle);
>       queue_work(dev_priv->wq, &dev_priv->idle_work);
>  }
>  
> @@ -5651,26 +5634,32 @@ static void intel_idle_update(struct work_struct 
> *work)
>                                                   idle_work);
>       struct drm_device *dev = dev_priv->dev;
>       struct drm_crtc *crtc;
> -     struct intel_crtc *intel_crtc;
> -
> -     if (!i915_powersave)
> -             return;
> +     unsigned idle;
>  
>       mutex_lock(&dev->struct_mutex);
>  
> -     i915_update_gfx_val(dev_priv);
> +     idle = atomic_xchg(&dev_priv->idle, 0);
> +     if (idle & (1 << 31))
> +             intel_sanitize_pm(dev);
>  
> +     if (!i915_powersave)
> +             goto unlock;
> +
> +     i915_update_gfx_val(dev_priv);
>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> +             struct intel_crtc *intel_crtc;
> +
>               /* Skip inactive CRTCs */
>               if (!crtc->fb)
>                       continue;
>  
>               intel_crtc = to_intel_crtc(crtc);
> -             if (!intel_crtc->busy)
> +             if (idle & (1 << intel_crtc->pipe))
>                       intel_decrease_pllclock(crtc);
>       }
>  
> -
> +unlock:
> +     dev_priv->busy &= ~idle;
>       mutex_unlock(&dev->struct_mutex);
>  }
>  
> @@ -5687,38 +5676,42 @@ static void intel_idle_update(struct work_struct 
> *work)
>  void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
>  {
>       drm_i915_private_t *dev_priv = dev->dev_private;
> -     struct drm_crtc *crtc = NULL;
> -     struct intel_framebuffer *intel_fb;
> -     struct intel_crtc *intel_crtc;
> -
> -     if (!drm_core_check_feature(dev, DRIVER_MODESET))
> -             return;
> +     struct drm_crtc *crtc;
> +     unsigned busy = 0;
>  
> -     if (!dev_priv->busy) {
> +     if ((dev_priv->busy & (1 << 31)) == 0) {
>               intel_sanitize_pm(dev);
> -             dev_priv->busy = true;
> -     } else
> -             mod_timer(&dev_priv->idle_timer, jiffies +
> -                       msecs_to_jiffies(GPU_IDLE_TIMEOUT));
> +             busy |= 1 << 31;
> +     }
> +
> +     if (!i915_powersave)
> +             goto out;
>  
>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> +             struct intel_crtc *intel_crtc;
> +
>               if (!crtc->fb)
>                       continue;
>  
>               intel_crtc = to_intel_crtc(crtc);
> -             intel_fb = to_intel_framebuffer(crtc->fb);
> -             if (intel_fb->obj == obj) {
> -                     if (!intel_crtc->busy) {
> +             if (to_intel_framebuffer(crtc->fb)->obj == obj) {
> +                     if ((dev_priv->busy & (1 << intel_crtc->pipe)) == 0) {
>                               /* Non-busy -> busy, upclock */
>                               intel_increase_pllclock(crtc);
> -                             intel_crtc->busy = true;
> -                     } else {
> -                             /* Busy -> busy, put off timer */
> -                             mod_timer(&intel_crtc->idle_timer, jiffies +
> -                                       msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
> +                             busy |= 1 << intel_crtc->pipe;
>                       }
> +
> +                     mod_timer(&intel_crtc->idle_timer, jiffies +
> +                               msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
>               }
>       }
> +
> +out:
> +     mod_timer(&dev_priv->idle_timer, jiffies +
> +               msecs_to_jiffies(GPU_IDLE_TIMEOUT));
> +
> +     atomic_clear_mask(busy, &dev_priv->idle);
> +     dev_priv->busy |= busy;
>  }
>  
>  static void intel_crtc_destroy(struct drm_crtc *crtc)
> @@ -6311,7 +6304,6 @@ static void intel_crtc_init(struct drm_device *dev, int 
> pipe)
>  
>       drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
>  
> -     intel_crtc->busy = false;
>       setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
>                   (unsigned long)intel_crtc);
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h 
> b/drivers/gpu/drm/i915/intel_drv.h
> index 0bd6d8a..64c2e7d 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -165,7 +165,6 @@ struct intel_crtc {
>       u8 lut_r[256], lut_g[256], lut_b[256];
>       int dpms_mode;
>       bool active; /* is the crtc on? independent of the dpms mode */
> -     bool busy; /* is scanout buffer being updated frequently? */
>       struct timer_list idle_timer;
>       bool lowfreq_avail;
>       struct intel_overlay *overlay;
> -- 
> 1.7.10
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Mail: dan...@ffwll.ch
Mobile: +41 (0)79 365 57 48
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to