@@ -534,6 +534,8 @@ struct i915_hw_ppgtt {
gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr,
enum i915_cache_level level);
int (*enable)(struct i915_hw_ppgtt *ppgtt);
+ int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
+ struct intel_ring_buffer *ring);
void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
};
@@ -122,11 +122,54 @@ static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
readl(pd_addr);
}
+static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ppgtt->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t pd_offset = ppgtt->pd_offset;
+ int ret;
+
+ pd_offset /= 64; /* in cachelines, */
+ pd_offset <<= 16;
+
+ /* 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)
+ */
+ if (i915_reset_in_progress(&dev_priv->gpu_error)) {
+ WARN_ON(ppgtt != dev_priv->gtt.aliasing_ppgtt);
+ I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+ I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
+ 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, pd_offset);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+
+ return 0;
+}
+
static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
{
struct drm_device *dev = ppgtt->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t pd_offset;
struct intel_ring_buffer *ring;
int i;
@@ -134,10 +177,6 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
gen6_write_pdes(ppgtt);
- pd_offset = ppgtt->pd_offset;
- pd_offset /= 64; /* in cachelines, */
- pd_offset <<= 16;
-
if (INTEL_INFO(dev)->gen == 6) {
uint32_t ecochk, gab_ctl, ecobits;
@@ -179,36 +218,9 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
I915_WRITE(RING_MODE_GEN7(ring),
_MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
- /* 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)
- */
- if (i915_reset_in_progress(&dev_priv->gpu_error)) {
- WARN_ON(ppgtt != dev_priv->gtt.aliasing_ppgtt);
- I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
- I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
- return 0;
- }
-
- /* NB: TLBs must be flushed and invalidated before a switch */
- ret = ring->flush(ring, I915_GEM_GPU_DOMAINS,
- I915_GEM_GPU_DOMAINS);
+ ret = ppgtt->switch_mm(ppgtt, ring);
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, pd_offset);
- intel_ring_emit(ring, MI_NOOP);
- intel_ring_advance(ring);
}
return 0;
}
@@ -375,6 +387,7 @@ alloc:
ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
ppgtt->enable = gen6_ppgtt_enable;
+ ppgtt->switch_mm = gen6_mm_switch;
ppgtt->cleanup = gen6_ppgtt_cleanup;
vm->clear_range = gen6_ppgtt_clear_range;
In order to do the full context switch with address space, it's convenient to have a way to switch the address space. We already have this in our code - just pull it out to be called by the context switch code later. Signed-off-by: Ben Widawsky <ben@bwidawsk.net> --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem_gtt.c | 79 +++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 33 deletions(-)