From 12638c57f31952127c734c26315e1348fa1334c2 Mon Sep 17 00:00:00 2001
From: Ben Widawsky <ben@bwidawsk.net>
Date: Tue, 28 May 2013 19:22:31 -0700
Subject: [PATCH] drm/i915: Enable vebox interrupts
Git-commit: 12638c57f31952127c734c26315e1348fa1334c2
Patch-mainline: 3.11-rc1
References: bnc#831103,FATE#316109

Similar to a patch originally written by:

V2: Reversed the meanings of masked and enabled (Haihao)
Made non-destructive writes in case enable/disabler rps runs first
(Haihao)

V3: Reword error message (Damien)
Modify postinstall to do the right thing based on previous fixup. (Ben)

Cc: Xiang, Haihao <haihao.xiang@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/gpu/drm/i915/i915_irq.c         |   31 +++++++++++++++++++++++++------
 drivers/gpu/drm/i915/i915_reg.h         |    3 +++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    3 ++-
 3 files changed, 30 insertions(+), 7 deletions(-)

--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -562,8 +562,15 @@ static void hsw_pm_irq_handler(struct dr
 	}
 	spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
 
-	if (pm_iir & ~GEN6_PM_RPS_EVENTS)
-		DRM_ERROR("Unexpected PM interrupted\n");
+	if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
+		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+			notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+
+		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+			DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+			i915_handle_error(dev_priv->dev, false);
+		}
+	}
 }
 
 static irqreturn_t valleyview_irq_handler(int irq, void *arg)
@@ -2088,6 +2095,7 @@ static int ivybridge_irq_postinstall(str
 		DE_PLANEB_FLIP_DONE_IVB |
 		DE_PLANEA_FLIP_DONE_IVB |
 		DE_AUX_CHANNEL_A_IVB;
+	u32 pm_irqs = GEN6_PM_RPS_EVENTS;
 	u32 gt_irqs;
 	u32 hotplug_mask;
 
@@ -2113,10 +2121,21 @@ static int ivybridge_irq_postinstall(str
 	I915_WRITE(GTIER, gt_irqs);
 	POSTING_READ(GTIER);
 
-	/* Power management */
-	I915_WRITE(GEN6_PMIMR, ~GEN6_PM_RPS_EVENTS);
-	I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
-	POSTING_READ(GEN6_PMIMR);
+	I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+	if (HAS_VEBOX(dev))
+		pm_irqs |= PM_VEBOX_USER_INTERRUPT |
+			PM_VEBOX_CS_ERROR_INTERRUPT;
+
+	/* Our enable/disable rps functions may touch these registers so
+	 * make sure to set a known state for only the non-RPS bits.
+	 * The RMW is extra paranoia since this should be called after being set
+	 * to a known state in preinstall.
+	 * */
+	I915_WRITE(GEN6_PMIMR,
+		   (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
+	I915_WRITE(GEN6_PMIER,
+		   (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
+	POSTING_READ(GEN6_PMIER);
 
 	hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
 			SDE_PORTB_HOTPLUG_CPT |
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -726,6 +726,9 @@
 #define GT_RENDER_DEBUG_INTERRUPT		(1 <<  1)
 #define GT_RENDER_USER_INTERRUPT		(1 <<  0)
 
+#define PM_VEBOX_CS_ERROR_INTERRUPT		(1 << 12) /* hsw+ */
+#define PM_VEBOX_USER_INTERRUPT			(1 << 10) /* hsw+ */
+
 /* These are all the "old" interrupts */
 #define ILK_BSD_USER_INTERRUPT				(1<<5)
 #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT		(1<<18)
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1929,7 +1929,8 @@ int intel_init_vebox_ring_buffer(struct
 	ring->flush = gen6_ring_flush;
 	ring->add_request = gen6_add_request;
 	ring->get_seqno = gen6_ring_get_seqno;
-	ring->irq_enable_mask = 0;
+	ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT |
+		PM_VEBOX_CS_ERROR_INTERRUPT;
 	ring->irq_get = hsw_vebox_get_irq;
 	ring->irq_put = hsw_vebox_put_irq;
 	ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
