[Intel-gfx] [PATCH 4/9] drm/i915: handle interrupt on new chipset

Zhenyu Wang zhenyuw at linux.intel.com
Fri Jun 5 09:38:39 CEST 2009


Update interrupt handling methods for IGDNG with new registers
for display and graphics interrupt functions.

Signed-off-by: Zhenyu Wang <zhenyuw at linux.intel.com>
---
 drivers/gpu/drm/i915/i915_dma.c |    2 +-
 drivers/gpu/drm/i915/i915_drv.h |    5 +
 drivers/gpu/drm/i915/i915_gem.c |    5 +-
 drivers/gpu/drm/i915/i915_irq.c |  228 +++++++++++++++++++++++++++++++++++++--
 4 files changed, 228 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 53d5445..e89560c 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1161,7 +1161,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 #endif
 
 	dev->driver->get_vblank_counter = i915_get_vblank_counter;
-	if (IS_GM45(dev))
+	if (IS_GM45(dev) || IS_IGDNG(dev))
 		dev->driver->get_vblank_counter = gm45_get_vblank_counter;
 
 	i915_gem_load(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 96f5279..97f9771 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -158,6 +158,11 @@ typedef struct drm_i915_private {
 	/** Cached value of IMR to avoid reads in updating the bitfield */
 	u32 irq_mask_reg;
 	u32 pipestat[2];
+	/** splitted irq regs for graphics and display engine on IGDNG,
+	    irq_mask_reg is still used for display irq. */
+	u32 gt_irq_mask_reg;
+	u32 gt_irq_enable_reg;
+	u32 de_irq_enable_reg;
 
 	u32 hotplug_supported_mask;
 	struct work_struct hotplug_work;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 670d128..cfc27aa 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1702,7 +1702,10 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno)
 	BUG_ON(seqno == 0);
 
 	if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
-		ier = I915_READ(IER);
+		if (IS_IGDNG(dev))
+			ier = I915_READ(DEIER) | I915_READ(GTIER);
+		else
+			ier = I915_READ(IER);
 		if (!ier) {
 			DRM_ERROR("something (likely vbetool) disabled "
 				  "interrupts, re-enabling\n");
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 98bb4c8..2314784 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -58,6 +58,34 @@
 					 DRM_I915_VBLANK_PIPE_B)
 
 void
+igdng_enable_irq(drm_i915_private_t *dev_priv, u32 mask, int gfx_irq)
+{
+	if (gfx_irq && ((dev_priv->gt_irq_mask_reg & mask) != 0)) {
+		dev_priv->gt_irq_mask_reg &= ~mask;
+		I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+		(void) I915_READ(GTIMR);
+	} else if ((dev_priv->irq_mask_reg & mask) != 0) {
+		dev_priv->irq_mask_reg &= ~mask;
+		I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+		(void) I915_READ(DEIMR);
+	}
+}
+
+static inline void
+igdng_disable_irq(drm_i915_private_t *dev_priv, u32 mask, int gfx_irq)
+{
+	if (gfx_irq && ((dev_priv->gt_irq_mask_reg & mask) != mask)) {
+		dev_priv->gt_irq_mask_reg |= mask;
+		I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+		(void) I915_READ(GTIMR);
+	} else if ((dev_priv->irq_mask_reg & mask) != mask) {
+		dev_priv->irq_mask_reg |= mask;
+		I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+		(void) I915_READ(DEIMR);
+	}
+}
+
+void
 i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
 	if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -196,6 +224,58 @@ static void i915_hotplug_work_func(struct work_struct *work)
 	drm_sysfs_hotplug_event(dev);
 }
 
+irqreturn_t igdng_irq_handler(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	int ret = IRQ_NONE;
+	u32 de_iir, gt_iir;
+	u32 new_de_iir, new_gt_iir;
+	int vblank = 0;
+	struct drm_i915_master_private *master_priv;
+
+	de_iir = I915_READ(DEIIR);
+	gt_iir = I915_READ(GTIIR);
+
+	for (;;) {
+		if (de_iir == 0 && gt_iir == 0)
+			break;
+
+		ret = IRQ_HANDLED;
+
+		I915_WRITE(DEIIR, de_iir);
+		new_de_iir = I915_READ(DEIIR);
+		I915_WRITE(GTIIR, gt_iir);
+		new_gt_iir = I915_READ(GTIIR);
+
+		if (dev->primary->master) {
+			master_priv = dev->primary->master->driver_priv;
+			if (master_priv->sarea_priv)
+				master_priv->sarea_priv->last_dispatch =
+					READ_BREADCRUMB(dev_priv);
+		}
+
+		if (gt_iir & GT_USER_INTERRUPT) {
+			dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
+			DRM_WAKEUP(&dev_priv->irq_queue);
+		}
+
+		if (de_iir & DE_PIPEA_VBLANK) {
+			vblank++;
+			drm_handle_vblank(dev, 0);
+		}
+
+		if (de_iir & DE_PIPEB_VBLANK) {
+			vblank++;
+			drm_handle_vblank(dev, 1);
+		}
+
+		de_iir = new_de_iir;
+		gt_iir = new_gt_iir;
+	}
+
+	return ret;
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
 	struct drm_device *dev = (struct drm_device *) arg;
@@ -212,6 +292,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
 	atomic_inc(&dev_priv->irq_received);
 
+	if (IS_IGDNG(dev))
+		return igdng_irq_handler(dev);
+
 	iir = I915_READ(IIR);
 
 	if (IS_I965G(dev)) {
@@ -349,8 +432,12 @@ void i915_user_irq_get(struct drm_device *dev)
 	unsigned long irqflags;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-	if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
-		i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+	if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
+		if (IS_IGDNG(dev))
+			igdng_enable_irq(dev_priv, GT_USER_INTERRUPT, 1);
+		else
+			i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+	}
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -361,8 +448,12 @@ void i915_user_irq_put(struct drm_device *dev)
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
-	if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
-		i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+	if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
+		if (IS_IGDNG(dev))
+			igdng_disable_irq(dev_priv, GT_USER_INTERRUPT, 1);
+		else
+			i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+	}
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -441,6 +532,43 @@ int i915_irq_wait(struct drm_device *dev, void *data,
 	return i915_wait_irq(dev, irqwait->irq_seq);
 }
 
+static void igdng_enable_vblank(struct drm_device *dev, int pipe)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	u32 vblank;
+
+	if (pipe == 0)
+		vblank = DE_PIPEA_VBLANK;
+	else
+		vblank = DE_PIPEB_VBLANK;
+
+	if ((dev_priv->de_irq_enable_reg & vblank) == 0) {
+		igdng_enable_irq(dev_priv, vblank, 0);
+		dev_priv->de_irq_enable_reg |= vblank;
+		I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
+		(void) I915_READ(DEIER);
+	}
+}
+
+static void igdng_disable_vblank(struct drm_device *dev, int pipe)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	u32 vblank;
+
+	if (pipe == 0)
+		vblank = DE_PIPEA_VBLANK;
+	else
+		vblank = DE_PIPEB_VBLANK;
+
+	if ((dev_priv->de_irq_enable_reg & vblank) != 0) {
+		igdng_disable_irq(dev_priv, vblank, 0);
+		dev_priv->de_irq_enable_reg &= ~vblank;
+		I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
+		(void) I915_READ(DEIER);
+	}
+}
+
+
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -456,7 +584,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
 		return -EINVAL;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-	if (IS_I965G(dev))
+	if (IS_IGDNG(dev))
+		igdng_enable_vblank(dev, pipe);
+	else if (IS_I965G(dev))
 		i915_enable_pipestat(dev_priv, pipe,
 				     PIPE_START_VBLANK_INTERRUPT_ENABLE);
 	else
@@ -475,9 +605,12 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
 	unsigned long irqflags;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-	i915_disable_pipestat(dev_priv, pipe,
-			      PIPE_VBLANK_INTERRUPT_ENABLE |
-			      PIPE_START_VBLANK_INTERRUPT_ENABLE);
+	if (IS_IGDNG(dev))
+		igdng_disable_vblank(dev, pipe);
+	else
+		i915_disable_pipestat(dev_priv, pipe,
+				      PIPE_VBLANK_INTERRUPT_ENABLE |
+				      PIPE_START_VBLANK_INTERRUPT_ENABLE);
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
@@ -545,12 +678,65 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 
 /* drm_dma.h hooks
 */
+static void igdng_irq_preinstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+	I915_WRITE(HWSTAM, 0xeffe);
+
+	/* XXX hotplug from PCH */
+
+	I915_WRITE(DEIMR, 0xffffffff);
+	I915_WRITE(DEIER, 0x0);
+	(void) I915_READ(DEIER);
+
+	/* and GT */
+	I915_WRITE(GTIMR, 0xffffffff);
+	I915_WRITE(GTIER, 0x0);
+	(void) I915_READ(GTIER);
+}
+
+static int igdng_irq_postinstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	/* enable kind of interrupts always enabled */
+	u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */;
+	u32 render_mask = GT_USER_INTERRUPT;
+
+	dev_priv->irq_mask_reg = ~display_mask;
+	dev_priv->de_irq_enable_reg = display_mask;
+
+	/* should always can generate irq */
+	I915_WRITE(DEIIR, I915_READ(DEIIR));
+	I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
+	I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
+	(void) I915_READ(DEIER);
+
+	/* user interrupt should be enabled, but masked initial */
+	dev_priv->gt_irq_mask_reg = 0xffffffff;
+	dev_priv->gt_irq_enable_reg = render_mask;
+
+	I915_WRITE(GTIIR, I915_READ(GTIIR));
+	I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
+	I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
+	(void) I915_READ(GTIER);
+
+	return 0;
+}
+
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
 	atomic_set(&dev_priv->irq_received, 0);
 
+	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+
+	if (IS_IGDNG(dev)) {
+		igdng_irq_preinstall(dev);
+		return;
+	}
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		I915_WRITE(PORT_HOTPLUG_EN, 0);
 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -562,7 +748,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
 	I915_WRITE(IMR, 0xffffffff);
 	I915_WRITE(IER, 0x0);
 	(void) I915_READ(IER);
-	INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
 }
 
 int i915_driver_irq_postinstall(struct drm_device *dev)
@@ -570,10 +755,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
 
+	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+
 	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
 	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
+	if (IS_IGDNG(dev))
+		return igdng_irq_postinstall(dev);
+
 	/* Unmask the interrupts that we always want on. */
 	dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
 
@@ -613,11 +803,24 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
 	(void) I915_READ(IER);
 
 	opregion_enable_asle(dev);
-	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
 
 	return 0;
 }
 
+static void igdng_irq_uninstall(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+	I915_WRITE(HWSTAM, 0xffffffff);
+
+	I915_WRITE(DEIMR, 0xffffffff);
+	I915_WRITE(DEIER, 0x0);
+	I915_WRITE(DEIIR, I915_READ(DEIIR));
+
+	I915_WRITE(GTIMR, 0xffffffff);
+	I915_WRITE(GTIER, 0x0);
+	I915_WRITE(GTIIR, I915_READ(GTIIR));
+}
+
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -627,6 +830,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
 
 	dev_priv->vblank_pipe = 0;
 
+	if (IS_IGDNG(dev)) {
+		igdng_irq_uninstall(dev);
+		return;
+	}
+
 	if (I915_HAS_HOTPLUG(dev)) {
 		I915_WRITE(PORT_HOTPLUG_EN, 0);
 		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-- 
1.6.3




More information about the Intel-gfx mailing list