drm/i915: Restore fences after resume and GPU resets

Stéphane Marchesin found that fences for pinned objects (i.e. the
scanout) were not being restored upon resume, leading to corruption on
the display and reference counting issues. This is due to a bug in

commit 312817a39f17dbb4de000165b5b724e3728cd91c [2.6.38]
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date: Mon Nov 22 11:50:11 2010 +0000

drm/i915: Only save and restore fences for UMS

that zapped the pinned fences even though they were in use.
Fortuitously, whilst we forced a VT switch during suspend and resume,
no fences were ever pinned at the time. However, we now can do
switchless S3 transitions and so the old bug finally surfaces.

Reported-by: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

authored by Chris Wilson and committed by Daniel Vetter 19b2dbde 7d132055

Changed files
+8 -17
drivers
+2
drivers/gpu/drm/i915/i915_drv.h
··· 1697 1697 struct dma_buf *i915_gem_prime_export(struct drm_device *dev, 1698 1698 struct drm_gem_object *gem_obj, int flags); 1699 1699 1700 + void i915_gem_restore_fences(struct drm_device *dev); 1701 + 1700 1702 /* i915_gem_context.c */ 1701 1703 void i915_gem_context_init(struct drm_device *dev); 1702 1704 void i915_gem_context_fini(struct drm_device *dev);
+5 -17
drivers/gpu/drm/i915/i915_gem.c
··· 2117 2117 } 2118 2118 } 2119 2119 2120 - static void i915_gem_reset_fences(struct drm_device *dev) 2120 + void i915_gem_restore_fences(struct drm_device *dev) 2121 2121 { 2122 2122 struct drm_i915_private *dev_priv = dev->dev_private; 2123 2123 int i; 2124 2124 2125 2125 for (i = 0; i < dev_priv->num_fence_regs; i++) { 2126 2126 struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; 2127 - 2128 - if (reg->obj) 2129 - i915_gem_object_fence_lost(reg->obj); 2130 - 2131 - i915_gem_write_fence(dev, i, NULL); 2132 - 2133 - reg->pin_count = 0; 2134 - reg->obj = NULL; 2135 - INIT_LIST_HEAD(&reg->lru_list); 2127 + i915_gem_write_fence(dev, i, reg->obj); 2136 2128 } 2137 - 2138 - INIT_LIST_HEAD(&dev_priv->mm.fence_list); 2139 2129 } 2140 2130 2141 2131 void i915_gem_reset(struct drm_device *dev) ··· 2148 2158 obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS; 2149 2159 } 2150 2160 2151 - /* The fence registers are invalidated so clear them out */ 2152 - i915_gem_reset_fences(dev); 2161 + i915_gem_restore_fences(dev); 2153 2162 } 2154 2163 2155 2164 /** ··· 3854 3865 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 3855 3866 i915_gem_evict_everything(dev); 3856 3867 3857 - i915_gem_reset_fences(dev); 3858 - 3859 3868 /* Hack! Don't let anybody do execbuf while we don't control the chip. 3860 3869 * We need to replace this with a semaphore, or something. 3861 3870 * And not confound mm.suspended! ··· 4180 4193 dev_priv->num_fence_regs = 8; 4181 4194 4182 4195 /* Initialize fence registers to zero */ 4183 - i915_gem_reset_fences(dev); 4196 + INIT_LIST_HEAD(&dev_priv->mm.fence_list); 4197 + i915_gem_restore_fences(dev); 4184 4198 4185 4199 i915_gem_detect_bit_6_swizzle(dev); 4186 4200 init_waitqueue_head(&dev_priv->pending_flip_queue);
+1
drivers/gpu/drm/i915/i915_suspend.c
··· 384 384 385 385 mutex_lock(&dev->struct_mutex); 386 386 387 + i915_gem_restore_fences(dev); 387 388 i915_restore_display(dev); 388 389 389 390 if (!drm_core_check_feature(dev, DRIVER_MODESET)) {