mirror of https://gitee.com/openkylin/linux.git
drm/i915: Retire any pending operations on the old scanout when switching
An old and oft reported bug, is that of the GPU hanging on a MI_WAIT_FOR_EVENT following a mode switch. The cause is that the GPU is waiting on a scanline counter on an inactive pipe, and so waits for a very long time until eventually the user reboots his machine. We can prevent this either by moving the WAIT into the kernel and thereby incurring considerable cost on every swapbuffers, or by waiting for the GPU to retire the last batch that accesses the framebuffer before installing a new one. As mode switches are much rarer than swap buffers, this looks like an easy choice. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=28964 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29252 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org
This commit is contained in:
parent
69669455b0
commit
85345517fe
|
@ -1045,6 +1045,8 @@ void i915_gem_clflush_object(struct drm_gem_object *obj);
|
||||||
int i915_gem_object_set_domain(struct drm_gem_object *obj,
|
int i915_gem_object_set_domain(struct drm_gem_object *obj,
|
||||||
uint32_t read_domains,
|
uint32_t read_domains,
|
||||||
uint32_t write_domain);
|
uint32_t write_domain);
|
||||||
|
int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
|
||||||
|
bool interruptible);
|
||||||
int i915_gem_init_ringbuffer(struct drm_device *dev);
|
int i915_gem_init_ringbuffer(struct drm_device *dev);
|
||||||
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
|
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
|
||||||
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
|
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
|
||||||
|
|
|
@ -2907,6 +2907,20 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
|
||||||
|
bool interruptible)
|
||||||
|
{
|
||||||
|
if (!obj->active)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (obj->base.write_domain & I915_GEM_GPU_DOMAINS)
|
||||||
|
i915_gem_flush_ring(obj->base.dev, NULL, obj->ring,
|
||||||
|
0, obj->base.write_domain);
|
||||||
|
|
||||||
|
return i915_gem_object_wait_rendering(&obj->base, interruptible);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves a single object to the CPU read, and possibly write domain.
|
* Moves a single object to the CPU read, and possibly write domain.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1611,6 +1611,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||||
|
|
||||||
wait_event(dev_priv->pending_flip_queue,
|
wait_event(dev_priv->pending_flip_queue,
|
||||||
atomic_read(&obj_priv->pending_flip) == 0);
|
atomic_read(&obj_priv->pending_flip) == 0);
|
||||||
|
|
||||||
|
/* Big Hammer, we also need to ensure that any pending
|
||||||
|
* MI_WAIT_FOR_EVENT inside a user batch buffer on the
|
||||||
|
* current scanout is retired before unpinning the old
|
||||||
|
* framebuffer.
|
||||||
|
*/
|
||||||
|
ret = i915_gem_object_flush_gpu(obj_priv, false);
|
||||||
|
if (ret) {
|
||||||
|
i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
|
||||||
|
mutex_unlock(&dev->struct_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
|
ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
|
||||||
|
|
Loading…
Reference in New Issue