aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Widawsky <benjamin.widawsky@intel.com>2013-11-03 00:07:00 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-11-07 16:16:04 -0500
commitab2aa47e4b2d2a74642c45f2e20fb9954f0fa8e1 (patch)
tree31c7648862beab750aa23e45acd06b62623d87cc
parentd2980845b7c45cb4305031eb5ea1891b11c4bc36 (diff)
drm/i915/bdw: Handle forcewake for writes on gen8
GEN8 removes the GT FIFO which we've all come to know and love. Instead it offers a wider range of optimized registers which always keep a shadowed copy, and are fed to the GPU when it wakes. How this is implemented in hardware is still somewhat of a mystery. As far as I can tell, the basic design is as follows: If the register is not optimized, you must use the old forcewake mechanism to bring the GT out of sleep. [1] If register is in the optimized list the write will signal that the GT should begin to come out of whatever sleep state it is in. While the GT is coming out of sleep, the requested write will be stored in an intermediate shadow register. Do to the fact that the implementation details are not clear, I see several risks: 1. Order is not preserved as it is with GT FIFO. If we issue multiple writes to optimized registers, where order matters, we may need to serialize it with forcewake. 2. The optimized registers have only 1 shadowed slot, meaning if we issue multiple writes to the same register, and those values need to reach the GPU in order, forcewake will be required. [1] We could implement a SW queue the way the GT FIFO used to work if desired. NOTE: Compile tested only until we get real silicon. v2: - Use a default case to make future platforms also work. - Get rid of IS_BROADWELL since that's not yet defined, but we want to MMIO as soon as possible. v3: Apply suggestions from Mika's review: - s/optimized/shadowed/ - invert the logic of the helper so that it does what it says (the code itself was correct, just confusing to read). v4: - Squash in lost break. Signed-off-by: Ben Widawsky <ben@bwidawsk.net> (v1) Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index f6fae35c568e..ccbbd6d5f10f 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -93,7 +93,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
93{ 93{
94 u32 forcewake_ack; 94 u32 forcewake_ack;
95 95
96 if (IS_HASWELL(dev_priv->dev)) 96 if (IS_HASWELL(dev_priv->dev) || IS_GEN8(dev_priv->dev))
97 forcewake_ack = FORCEWAKE_ACK_HSW; 97 forcewake_ack = FORCEWAKE_ACK_HSW;
98 else 98 else
99 forcewake_ack = FORCEWAKE_MT_ACK; 99 forcewake_ack = FORCEWAKE_MT_ACK;
@@ -459,6 +459,46 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
459 spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ 459 spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
460} 460}
461 461
462static const u32 gen8_shadowed_regs[] = {
463 FORCEWAKE_MT,
464 GEN6_RPNSWREQ,
465 GEN6_RC_VIDEO_FREQ,
466 RING_TAIL(RENDER_RING_BASE),
467 RING_TAIL(GEN6_BSD_RING_BASE),
468 RING_TAIL(VEBOX_RING_BASE),
469 RING_TAIL(BLT_RING_BASE),
470 /* TODO: Other registers are not yet used */
471};
472
473static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
474{
475 int i;
476 for (i = 0; i < ARRAY_SIZE(gen8_shadowed_regs); i++)
477 if (reg == gen8_shadowed_regs[i])
478 return true;
479
480 return false;
481}
482
483#define __gen8_write(x) \
484static void \
485gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
486 bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \
487 REG_WRITE_HEADER; \
488 if (__needs_put) { \
489 dev_priv->uncore.funcs.force_wake_get(dev_priv); \
490 } \
491 __raw_i915_write##x(dev_priv, reg, val); \
492 if (__needs_put) { \
493 dev_priv->uncore.funcs.force_wake_put(dev_priv); \
494 } \
495 spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
496}
497
498__gen8_write(8)
499__gen8_write(16)
500__gen8_write(32)
501__gen8_write(64)
462__hsw_write(8) 502__hsw_write(8)
463__hsw_write(16) 503__hsw_write(16)
464__hsw_write(32) 504__hsw_write(32)
@@ -476,6 +516,7 @@ __gen4_write(16)
476__gen4_write(32) 516__gen4_write(32)
477__gen4_write(64) 517__gen4_write(64)
478 518
519#undef __gen8_write
479#undef __hsw_write 520#undef __hsw_write
480#undef __gen6_write 521#undef __gen6_write
481#undef __gen5_write 522#undef __gen5_write
@@ -534,6 +575,16 @@ void intel_uncore_init(struct drm_device *dev)
534 } 575 }
535 576
536 switch (INTEL_INFO(dev)->gen) { 577 switch (INTEL_INFO(dev)->gen) {
578 default:
579 dev_priv->uncore.funcs.mmio_writeb = gen8_write8;
580 dev_priv->uncore.funcs.mmio_writew = gen8_write16;
581 dev_priv->uncore.funcs.mmio_writel = gen8_write32;
582 dev_priv->uncore.funcs.mmio_writeq = gen8_write64;
583 dev_priv->uncore.funcs.mmio_readb = gen6_read8;
584 dev_priv->uncore.funcs.mmio_readw = gen6_read16;
585 dev_priv->uncore.funcs.mmio_readl = gen6_read32;
586 dev_priv->uncore.funcs.mmio_readq = gen6_read64;
587 break;
537 case 7: 588 case 7:
538 case 6: 589 case 6:
539 if (IS_HASWELL(dev)) { 590 if (IS_HASWELL(dev)) {