Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb64343c authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915: Extract PIPESTAT irq handling into separate functions



Extract the gen2-4 PIPESTAT irq handling into separate functions just
like we already do on VLV/CHV.

We can share valleyview_pipestat_irq_ack() on all gmch platforms to
actually read and clear the PIPESTAT status bits, so let's rename
it to i9xx_pipestat_irq_ack().

Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170818183705.27850-11-ville.syrjala@linux.intel.com
parent 9515d7b8
Loading
Loading
Loading
Loading
+93 −122
Original line number Diff line number Diff line
@@ -1755,7 +1755,7 @@ static void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
	}
}

static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
static void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
				  u32 iir, u32 pipe_stats[I915_MAX_PIPES])
{
	int pipe;
@@ -1813,6 +1813,74 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
	spin_unlock(&dev_priv->irq_lock);
}

static void i8xx_pipestat_irq_handler(struct drm_i915_private *dev_priv,
				      u16 iir, u32 pipe_stats[I915_MAX_PIPES])
{
	enum pipe pipe;

	for_each_pipe(dev_priv, pipe) {
		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
			drm_handle_vblank(&dev_priv->drm, pipe);

		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
			i9xx_pipe_crc_irq_handler(dev_priv, pipe);

		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
	}
}

static void i915_pipestat_irq_handler(struct drm_i915_private *dev_priv,
				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
{
	bool blc_event = false;
	enum pipe pipe;

	for_each_pipe(dev_priv, pipe) {
		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
			drm_handle_vblank(&dev_priv->drm, pipe);

		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
			blc_event = true;

		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
			i9xx_pipe_crc_irq_handler(dev_priv, pipe);

		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
	}

	if (blc_event || (iir & I915_ASLE_INTERRUPT))
		intel_opregion_asle_intr(dev_priv);
}

static void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
{
	bool blc_event = false;
	enum pipe pipe;

	for_each_pipe(dev_priv, pipe) {
		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
			drm_handle_vblank(&dev_priv->drm, pipe);

		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
			blc_event = true;

		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
			i9xx_pipe_crc_irq_handler(dev_priv, pipe);

		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
	}

	if (blc_event || (iir & I915_ASLE_INTERRUPT))
		intel_opregion_asle_intr(dev_priv);

	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
		gmbus_irq_handler(dev_priv);
}

static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
					    u32 pipe_stats[I915_MAX_PIPES])
{
@@ -1928,7 +1996,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)

		/* Call regardless, as some status bits might not be
		 * signalled in iir */
		valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);

		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
			   I915_LPE_PIPE_B_INTERRUPT))
@@ -2012,7 +2080,7 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)

		/* Call regardless, as some status bits might not be
		 * signalled in iir */
		valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);

		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
			   I915_LPE_PIPE_B_INTERRUPT |
@@ -3630,8 +3698,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
	struct drm_device *dev = arg;
	struct drm_i915_private *dev_priv = to_i915(dev);
	u16 iir, new_iir;
	u32 pipe_stats[2];
	int pipe;
	irqreturn_t ret;

	if (!intel_irqs_enabled(dev_priv))
@@ -3646,26 +3712,14 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
		goto out;

	while (iir) {
		/* Can't rely on pipestat interrupt bit in iir as it might
		 * have been cleared after the pipestat interrupt was received.
		 * It doesn't set the bit in iir again, but it still produces
		 * interrupts (for non-MSI).
		 */
		spin_lock(&dev_priv->irq_lock);
		u32 pipe_stats[I915_MAX_PIPES] = {};

		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);

		for_each_pipe(dev_priv, pipe) {
			i915_reg_t reg = PIPESTAT(pipe);
			pipe_stats[pipe] = I915_READ(reg);

			/*
			 * Clear the PIPE*STAT regs before the IIR
			 */
			if (pipe_stats[pipe] & 0x8000ffff)
				I915_WRITE(reg, pipe_stats[pipe]);
		}
		spin_unlock(&dev_priv->irq_lock);
		/* Call regardless, as some status bits might not be
		 * signalled in iir */
		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);

		I915_WRITE16(IIR, iir);
		new_iir = I915_READ16(IIR); /* Flush posted writes */
@@ -3673,21 +3727,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
		if (iir & I915_USER_INTERRUPT)
			notify_ring(dev_priv->engine[RCS]);

		for_each_pipe(dev_priv, pipe) {
			int plane = pipe;
			if (HAS_FBC(dev_priv))
				plane = !plane;

			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
				drm_handle_vblank(&dev_priv->drm, pipe);

			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
				i9xx_pipe_crc_irq_handler(dev_priv, pipe);

			if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
				intel_cpu_fifo_underrun_irq_handler(dev_priv,
								    pipe);
		}
		i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats);

		iir = new_iir;
	}
@@ -3769,8 +3809,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
{
	struct drm_device *dev = arg;
	struct drm_i915_private *dev_priv = to_i915(dev);
	u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
	int pipe, ret = IRQ_NONE;
	u32 iir, new_iir;
	int ret = IRQ_NONE;

	if (!intel_irqs_enabled(dev_priv))
		return IRQ_NONE;
@@ -3780,29 +3820,15 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)

	iir = I915_READ(IIR);
	do {
		bool irq_received = (iir) != 0;
		bool blc_event = false;
		u32 pipe_stats[I915_MAX_PIPES] = {};
		bool irq_received = iir != 0;

		/* Can't rely on pipestat interrupt bit in iir as it might
		 * have been cleared after the pipestat interrupt was received.
		 * It doesn't set the bit in iir again, but it still produces
		 * interrupts (for non-MSI).
		 */
		spin_lock(&dev_priv->irq_lock);
		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);

		for_each_pipe(dev_priv, pipe) {
			i915_reg_t reg = PIPESTAT(pipe);
			pipe_stats[pipe] = I915_READ(reg);

			/* Clear the PIPE*STAT regs before the IIR */
			if (pipe_stats[pipe] & 0x8000ffff) {
				I915_WRITE(reg, pipe_stats[pipe]);
				irq_received = true;
			}
		}
		spin_unlock(&dev_priv->irq_lock);
		/* Call regardless, as some status bits might not be
		 * signalled in iir */
		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);

		if (!irq_received)
			break;
@@ -3821,27 +3847,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
		if (iir & I915_USER_INTERRUPT)
			notify_ring(dev_priv->engine[RCS]);

		for_each_pipe(dev_priv, pipe) {
			int plane = pipe;
			if (HAS_FBC(dev_priv))
				plane = !plane;

			if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
				drm_handle_vblank(&dev_priv->drm, pipe);

			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
				blc_event = true;

			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
				i9xx_pipe_crc_irq_handler(dev_priv, pipe);

			if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
				intel_cpu_fifo_underrun_irq_handler(dev_priv,
								    pipe);
		}

		if (blc_event || (iir & I915_ASLE_INTERRUPT))
			intel_opregion_asle_intr(dev_priv);
		i915_pipestat_irq_handler(dev_priv, iir, pipe_stats);

		/* With MSI, interrupts are only generated when iir
		 * transitions from zero to nonzero.  If another bit got
@@ -3982,8 +3988,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
	struct drm_device *dev = arg;
	struct drm_i915_private *dev_priv = to_i915(dev);
	u32 iir, new_iir;
	u32 pipe_stats[I915_MAX_PIPES];
	int ret = IRQ_NONE, pipe;
	int ret = IRQ_NONE;

	if (!intel_irqs_enabled(dev_priv))
		return IRQ_NONE;
@@ -3994,31 +3999,15 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
	iir = I915_READ(IIR);

	for (;;) {
		bool irq_received = (iir) != 0;
		bool blc_event = false;
		u32 pipe_stats[I915_MAX_PIPES] = {};
		bool irq_received = iir != 0;

		/* Can't rely on pipestat interrupt bit in iir as it might
		 * have been cleared after the pipestat interrupt was received.
		 * It doesn't set the bit in iir again, but it still produces
		 * interrupts (for non-MSI).
		 */
		spin_lock(&dev_priv->irq_lock);
		if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
			DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);

		for_each_pipe(dev_priv, pipe) {
			i915_reg_t reg = PIPESTAT(pipe);
			pipe_stats[pipe] = I915_READ(reg);

			/*
			 * Clear the PIPE*STAT regs before the IIR
			 */
			if (pipe_stats[pipe] & 0x8000ffff) {
				I915_WRITE(reg, pipe_stats[pipe]);
				irq_received = true;
			}
		}
		spin_unlock(&dev_priv->irq_lock);
		/* Call regardless, as some status bits might not be
		 * signalled in iir */
		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);

		if (!irq_received)
			break;
@@ -4040,25 +4029,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
		if (iir & I915_BSD_USER_INTERRUPT)
			notify_ring(dev_priv->engine[VCS]);

		for_each_pipe(dev_priv, pipe) {
			if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
				drm_handle_vblank(&dev_priv->drm, pipe);

			if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
				blc_event = true;

			if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
				i9xx_pipe_crc_irq_handler(dev_priv, pipe);

			if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
				intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
		}

		if (blc_event || (iir & I915_ASLE_INTERRUPT))
			intel_opregion_asle_intr(dev_priv);

		if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
			gmbus_irq_handler(dev_priv);
		i965_pipestat_irq_handler(dev_priv, iir, pipe_stats);

		/* With MSI, interrupts are only generated when iir
		 * transitions from zero to nonzero.  If another bit got