On Sat, Oct 15, 2011 at 01:47:16PM -0700, Ben Widawsky wrote:
> Idle the GPU before doing any unmaps. We know if VT-d is in use through
> an exported variable from iommu code.
> 
> This should avoid a known HW issue.
> 
> Signed-off-by: Ben Widawsky <b...@bwidawsk.net>
> ---
>  drivers/char/agp/intel-gtt.c        |   28 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/i915_drv.h     |    2 +-
>  drivers/gpu/drm/i915/i915_gem.c     |    4 +++-
>  drivers/gpu/drm/i915/i915_gem_gtt.c |   19 ++++++++++++++++++-
>  include/drm/intel-gtt.h             |    2 ++
>  5 files changed, 52 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
> index 8515101..80a7ed0 100644
> --- a/drivers/char/agp/intel-gtt.c
> +++ b/drivers/char/agp/intel-gtt.c
> @@ -923,6 +923,9 @@ static int intel_fake_agp_insert_entries(struct 
> agp_memory *mem,
>  {
>       int ret = -EINVAL;
>  
> +     if (intel_private.base.do_idle_maps)
> +             return -ENODEV;
> +
>       if (intel_private.clear_fake_agp) {
>               int start = intel_private.base.stolen_size / PAGE_SIZE;
>               int end = intel_private.base.gtt_mappable_entries;
> @@ -985,6 +988,9 @@ static int intel_fake_agp_remove_entries(struct 
> agp_memory *mem,
>       if (mem->page_count == 0)
>               return 0;
>  
> +     if (intel_private.base.do_idle_maps)
> +             return -ENODEV;
> +

This reminds me to kill the fake agp driver fro gen5+ with fire (we only
need it for ums code). Infrastructure is half-way there, but not quite yet
...

>       intel_gtt_clear_range(pg_start, mem->page_count);
>  
>       if (intel_private.base.needs_dmar) {
> @@ -1177,6 +1183,25 @@ static void gen6_cleanup(void)
>  {
>  }
>  
> +/* Certain Gen5 chipsets require require idling the GPU before
> + * unmapping anything from the GTT when VT-d is enabled.
> + */
> +extern int intel_iommu_gfx_mapped;
> +static inline int needs_idle_maps(void)
> +{
> +     const unsigned short gpu_devid = intel_private.pcidev->device;
> +
> +     /* Query intel_iommu to see if we need the workaround. Presumably that
> +      * was loaded first.
> +      */
> +     if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
> +          gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
> +          intel_iommu_gfx_mapped)
> +             return 1;
> +
> +     return 0;
> +}
> +
>  static int i9xx_setup(void)
>  {
>       u32 reg_addr;
> @@ -1211,6 +1236,9 @@ static int i9xx_setup(void)
>               intel_private.gtt_bus_addr = reg_addr + gtt_offset;
>       }
>  
> +     if (needs_idle_maps());
> +             intel_private.base.do_idle_maps = 1;
> +
>       intel_i9xx_setup_flush();
>  
>       return 0;
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 15c0ca5..3aa8612 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1219,7 +1219,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device 
> *dev);
>  int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
>  void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
>                               enum i915_cache_level cache_level);
> -void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
> +int i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
>  
>  /* i915_gem_evict.c */
>  int __must_check i915_gem_evict_something(struct drm_device *dev, int 
> min_size,
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index a925141..89d22eb 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2130,7 +2130,9 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
>  
>       trace_i915_gem_object_unbind(obj);
>  
> -     i915_gem_gtt_unbind_object(obj);
> +     ret = i915_gem_gtt_unbind_object(obj);
> +     if (ret == -ERESTARTSYS)
> +             return ret;
>       i915_gem_object_put_pages_gtt(obj);
>  
>       list_del_init(&obj->gtt_list);
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c 
> b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 7a709cd..1df6395 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -49,6 +49,15 @@ static unsigned int cache_level_to_agp_type(struct 
> drm_device *dev,
>       }
>  }
>  
> +static bool do_idling(struct drm_i915_private *dev_priv)
> +{
> +     if (dev_priv->mm.gtt->do_idle_maps)
> +             if (i915_gpu_idle(dev_priv->dev))
> +                     return false;
> +
> +     return true;
> +}
> +
>  void i915_gem_restore_gtt_mappings(struct drm_device *dev)
>  {
>       struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -115,8 +124,14 @@ void i915_gem_gtt_rebind_object(struct 
> drm_i915_gem_object *obj,
>                                      agp_type);
>  }
>  
> -void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
> +int i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
>  {
> +     struct drm_device *dev = obj->base.dev;
> +     struct drm_i915_private *dev_priv = dev->dev_private;
> +
> +     if (do_idling(dev_priv) == false)
> +             return -ERESTARTSYS;

That's a bit a lie, gpu_idle can also return -ENOMEM, -EAGAIN and -EIO. I
think you could just inline do_idling to avoid passing back the retval
twice ...
                
> +
>       intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
>                             obj->base.size >> PAGE_SHIFT);
>  
> @@ -124,4 +139,6 @@ void i915_gem_gtt_unbind_object(struct 
> drm_i915_gem_object *obj)
>               intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
>               obj->sg_list = NULL;
>       }
> +
> +     return 0;
>  }
> diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
> index 9e343c0..b174620 100644
> --- a/include/drm/intel-gtt.h
> +++ b/include/drm/intel-gtt.h
> @@ -13,6 +13,8 @@ const struct intel_gtt {
>       unsigned int gtt_mappable_entries;
>       /* Whether i915 needs to use the dmar apis or not. */
>       unsigned int needs_dmar : 1;
> +     /* Whether we idle the gpu before mapping/unmapping */
> +     unsigned int do_idle_maps : 1;
>  } *intel_gtt_get(void);
>  
>  void intel_gtt_chipset_flush(void);
> -- 
> 1.7.7
> 
> _______________________________________________
> 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