summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2013-07-04 09:49:01 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2013-07-04 09:49:01 +0000
commit74897b0fb7b61f8a1968bb922245a6e4ebabb9f6 (patch)
tree87dde47e671cad296dacf3726eb84efba0accd10 /sys/dev
parente1aada3a39aae8b4fc94078d06ef69a6eeed84b4 (diff)
Workaround incoherence between fences and LLC across multiple CPUs
from linux 3.8.13 this does not currently do the ipi to run wbinvd() on all processors
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/drm/i915/i915_gem.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/sys/dev/pci/drm/i915/i915_gem.c b/sys/dev/pci/drm/i915/i915_gem.c
index 4fbc43047ec..6c15b56f2d8 100644
--- a/sys/dev/pci/drm/i915/i915_gem.c
+++ b/sys/dev/pci/drm/i915/i915_gem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i915_gem.c,v 1.25 2013/06/12 14:28:40 kettenis Exp $ */
+/* $OpenBSD: i915_gem.c,v 1.26 2013/07/04 09:49:00 jsg Exp $ */
/*
* Copyright (c) 2008-2009 Owain G. Ainsworth <oga@openbsd.org>
*
@@ -1925,18 +1925,43 @@ fence_number(drm_i915_private_t *dev_priv,
return fence - dev_priv->fence_regs;
}
+#ifdef __linux__
+void
+i915_gem_write_fence__ipi(void *data)
+{
+ wbinvd();
+}
+#endif
+
void
i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
struct drm_i915_fence_reg *fence,
bool enable)
{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- int reg = fence_number(dev_priv, fence);
-
- i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
+ struct drm_device *dev = obj->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int fence_reg = fence_number(dev_priv, fence);
+
+ /* 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+. In theory, the write to the fence register
+ * flushes all memory transactions before, and coupled with the
+ * mb() placed around the register write we serialise all memory
+ * operations with respect to the changes in the tiler. Yet, on
+ * SNB+ we need to take a step further and emit an explicit wbinvd()
+ * on each processor in order to manually flush all memory
+ * transactions before updating the fence register.
+ */
+ if (HAS_LLC(obj->base.dev))
+#ifdef __linux__
+ on_each_cpu(i915_gem_write_fence__ipi, NULL, 1);
+#else
+ wbinvd();
+#endif
+ i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL);
if (enable) {
- obj->fence_reg = reg;
+ obj->fence_reg = fence_reg;
fence->obj = obj;
list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
} else {