|
@@ -486,6 +486,50 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
|
|
|
return (ppgtt->pd_offset / 64) << 16;
|
|
|
}
|
|
|
|
|
|
+static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
|
|
+ struct intel_ring_buffer *ring,
|
|
|
+ bool synchronous)
|
|
|
+{
|
|
|
+ struct drm_device *dev = ppgtt->base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* If we're in reset, we can assume the GPU is sufficiently idle to
|
|
|
+ * manually frob these bits. Ideally we could use the ring functions,
|
|
|
+ * except our error handling makes it quite difficult (can't use
|
|
|
+ * intel_ring_begin, ring->flush, or intel_ring_advance)
|
|
|
+ *
|
|
|
+ * FIXME: We should try not to special case reset
|
|
|
+ */
|
|
|
+ if (synchronous ||
|
|
|
+ i915_reset_in_progress(&dev_priv->gpu_error)) {
|
|
|
+ WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
|
|
|
+ I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
|
|
|
+ I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
|
|
|
+ POSTING_READ(RING_PP_DIR_BASE(ring));
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* NB: TLBs must be flushed and invalidated before a switch */
|
|
|
+ ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = intel_ring_begin(ring, 6);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
|
|
|
+ intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
|
|
|
+ intel_ring_emit(ring, PP_DIR_DCLV_2G);
|
|
|
+ intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
|
|
|
+ intel_ring_emit(ring, get_pd_offset(ppgtt));
|
|
|
+ intel_ring_emit(ring, MI_NOOP);
|
|
|
+ intel_ring_advance(ring);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
|
|
struct intel_ring_buffer *ring,
|
|
|
bool synchronous)
|
|
@@ -527,6 +571,13 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
|
|
intel_ring_emit(ring, MI_NOOP);
|
|
|
intel_ring_advance(ring);
|
|
|
|
|
|
+ /* XXX: RCS is the only one to auto invalidate the TLBs? */
|
|
|
+ if (ring->id != RCS) {
|
|
|
+ ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -762,6 +813,9 @@ alloc:
|
|
|
if (IS_GEN6(dev)) {
|
|
|
ppgtt->enable = gen6_ppgtt_enable;
|
|
|
ppgtt->switch_mm = gen6_mm_switch;
|
|
|
+ } else if (IS_HASWELL(dev)) {
|
|
|
+ ppgtt->enable = gen7_ppgtt_enable;
|
|
|
+ ppgtt->switch_mm = hsw_mm_switch;
|
|
|
} else if (IS_GEN7(dev)) {
|
|
|
ppgtt->enable = gen7_ppgtt_enable;
|
|
|
ppgtt->switch_mm = gen7_mm_switch;
|