aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson2013-04-04 15:31:03 -0500
committerGreg Kroah-Hartman2013-05-11 15:54:01 -0500
commitb578b3a82d830e2170d403b1fb29b649e26a48fb (patch)
tree2d692c72bc3b25268c8b34347a04efb15d510bd1
parent1501dd0e01575bda28dccc92a1b260abf3d29038 (diff)
downloadkernel-omap-b578b3a82d830e2170d403b1fb29b649e26a48fb.tar.gz
kernel-omap-b578b3a82d830e2170d403b1fb29b649e26a48fb.tar.xz
kernel-omap-b578b3a82d830e2170d403b1fb29b649e26a48fb.zip
drm/i915: Workaround incoherence between fences and LLC across multiple CPUs
commit 25ff1195f8a0b3724541ae7bbe331b4296de9c06 upstream. In order to fully serialize access to the fenced region and the update to the fence register we need to take extreme measures on SNB+, and manually flush writes to memory prior to writing the fence register in conjunction with the memory barriers placed around the register write. Fixes i-g-t/gem_fence_thrash v2: Bring a bigger gun v3: Switch the bigger gun for heavier bullets (Arjan van de Ven) v4: Remove changes for working generations. v5: Reduce to a per-cpu wbinvd() call prior to updating the fences. v6: Rewrite comments to ellide forgotten history. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=62191 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Jon Bloomfield <jon.bloomfield@intel.com> Tested-by: Jon Bloomfield <jon.bloomfield@intel.com> (v2) Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index de45b60516e6..3b9d18b9e92e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2662,17 +2662,35 @@ static inline int fence_number(struct drm_i915_private *dev_priv,
2662 return fence - dev_priv->fence_regs; 2662 return fence - dev_priv->fence_regs;
2663} 2663}
2664 2664
2665static void i915_gem_write_fence__ipi(void *data)
2666{
2667 wbinvd();
2668}
2669
2665static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, 2670static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
2666 struct drm_i915_fence_reg *fence, 2671 struct drm_i915_fence_reg *fence,
2667 bool enable) 2672 bool enable)
2668{ 2673{
2669 struct drm_i915_private *dev_priv = obj->base.dev->dev_private; 2674 struct drm_device *dev = obj->base.dev;
2670 int reg = fence_number(dev_priv, fence); 2675 struct drm_i915_private *dev_priv = dev->dev_private;
2671 2676 int fence_reg = fence_number(dev_priv, fence);
2672 i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); 2677
2678 /* In order to fully serialize access to the fenced region and
2679 * the update to the fence register we need to take extreme
2680 * measures on SNB+. In theory, the write to the fence register
2681 * flushes all memory transactions before, and coupled with the
2682 * mb() placed around the register write we serialise all memory
2683 * operations with respect to the changes in the tiler. Yet, on
2684 * SNB+ we need to take a step further and emit an explicit wbinvd()
2685 * on each processor in order to manually flush all memory
2686 * transactions before updating the fence register.
2687 */
2688 if (HAS_LLC(obj->base.dev))
2689 on_each_cpu(i915_gem_write_fence__ipi, NULL, 1);
2690 i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL);
2673 2691
2674 if (enable) { 2692 if (enable) {
2675 obj->fence_reg = reg; 2693 obj->fence_reg = fence_reg;
2676 fence->obj = obj; 2694 fence->obj = obj;
2677 list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); 2695 list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
2678 } else { 2696 } else {