Linux Archive

Linux Archive (http://www.linux-archive.org/)
-   Debian Kernel (http://www.linux-archive.org/debian-kernel/)
-   -   Bug#655152: *ERROR* Prepared flip multiple times (http://www.linux-archive.org/debian-kernel/696113-bug-655152-error-prepared-flip-multiple-times.html)

Jonathan Nieder 08-20-2012 11:05 PM

Bug#655152: *ERROR* Prepared flip multiple times
 
tags 655152 + upstream patch moreinfo
quit

Hi,

Sten Heinze wrote:

> Please backport the patch merged in Linux to the Debian kernel. The
> patch is in the upstream 3.5 kernel and references the bug
> freedesktop.org bug report:
>
> [...]h=c2798b19bac2538393fc932bfbe59807a4734b3e

Sounds like a good idea.

[...]
> drivers/gpu/drm/i915/i915_irq.c | 161 ++++++++++++++++++++++++++++++-
> drivers/gpu/drm/i915/intel_ringbuffer.c | 53 +++++++++-
> 2 files changed, 206 insertions(+), 8 deletions(-)

(generic grumble about patches that could have been split into smaller
--- in this example, two --- digestible pieces goes here)

Please test the attached patch against a 3.2.y kernel, for example
using the following instructions:

0. prerequisites:

apt-get install git build-essential

1. get the kernel history, if you don't already have it:

git clone
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

2. fetch point releases:

cd linux
git remote add stable
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
git fetch stable

3. configure, build, test:

git checkout stable/linux-3.2.y
cp /boot/config-$(uname -r) .config; # current configuration
scripts/config --disable DEBUG_INFO
make localmodconfig; # optional: minimize configuration
make deb-pkg; # optionally with -j<num> for parallel build
dpkg -i ../<name of package>; # as root
reboot
...test test test ...

Hopefully it reproduces the bug. So:

4. try the patch:

cd linux
git am -3sc /path/to/the/patch
make deb-pkg; # maybe with -j4
dpkg -i ../<name of package>; # as root
reboot
... test test test ...

Hope that helps,
Jonathan
From: Chris Wilson <chris@chris-wilson.co.uk>
Date: Sun, 22 Apr 2012 21:13:57 +0100
Subject: drm/i915: i8xx interrupt handler

commit c2798b19bac2538393fc932bfbe59807a4734b3e upstream.

gen2 hardware has some significant differences from the other interrupt
routines that were glossed over and then forgotten about in the
transition to KMS. Such as

- 16bit IIR
- PendingFlip status bit

This patch reintroduces a handler specifically for gen2 for the purpose
of handling pageflips correctly, simplifying code in the process.

v2: Also fixup ring get/put irq to only access 16bit registers (Daniel)

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=24202
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41793
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
[danvet: use posting_read16 in intel_ringbuffer.c and kill _driver
from the function names.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
[jn: check for gen2 directly in i915_enable_irq and i915_disable_irq
to simplify backport]
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
drivers/gpu/drm/i915/i915_irq.c | 161 ++++++++++++++++++++++++++++++-
drivers/gpu/drm/i915/intel_ringbuffer.c | 18 +++-
2 files changed, 171 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 578ddfc..ac5a50d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2083,6 +2083,152 @@ static void i915_driver_irq_uninstall(struct drm_device * dev)
I915_WRITE(IIR, I915_READ(IIR));
}

+static void i8xx_irq_preinstall(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ atomic_set(&dev_priv->irq_received, 0);
+
+ for_each_pipe(pipe)
+ I915_WRITE(PIPESTAT(pipe), 0);
+ I915_WRITE16(IMR, 0xffff);
+ I915_WRITE16(IER, 0x0);
+ POSTING_READ16(IER);
+}
+
+static int i8xx_irq_postinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+
+ dev_priv->pipestat[0] = 0;
+ dev_priv->pipestat[1] = 0;
+
+ I915_WRITE16(EMR,
+ ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
+
+ /* Unmask the interrupts that we always want on. */
+ dev_priv->irq_mask =
+ ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+ I915_WRITE16(IMR, dev_priv->irq_mask);
+
+ I915_WRITE16(IER,
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
+ I915_USER_INTERRUPT);
+ POSTING_READ16(IER);
+
+ return 0;
+}
+
+static irqreturn_t i8xx_irq_handler(DRM_IRQ_ARGS)
+{
+ struct drm_device *dev = (struct drm_device *) arg;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_master_private *master_priv;
+ u16 iir, new_iir;
+ u32 pipe_stats[2];
+ unsigned long irqflags;
+ int irq_received;
+ int pipe;
+ u16 flip_mask =
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+
+ atomic_inc(&dev_priv->irq_received);
+
+ iir = I915_READ16(IIR);
+ if (iir == 0)
+ return IRQ_NONE;
+
+ while (iir & ~flip_mask) {
+ /* 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_irqsave(&dev_priv->irq_lock, irqflags);
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+ i915_handle_error(dev, false);
+
+ for_each_pipe(pipe) {
+ int reg = PIPESTAT(pipe);
+ pipe_stats[pipe] = I915_READ(reg);
+
+ /*
+ * Clear the PIPE*STAT regs before the IIR
+ */
+ if (pipe_stats[pipe] & 0x8000ffff) {
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ DRM_DEBUG_DRIVER("pipe %c underrun
",
+ pipe_name(pipe));
+ I915_WRITE(reg, pipe_stats[pipe]);
+ irq_received = 1;
+ }
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ I915_WRITE16(IIR, iir & ~flip_mask);
+ new_iir = I915_READ16(IIR); /* Flush posted writes */
+
+ 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 (iir & I915_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[RCS]);
+
+ if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ drm_handle_vblank(dev, 0)) {
+ if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
+ intel_prepare_page_flip(dev, 0);
+ intel_finish_page_flip(dev, 0);
+ flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
+ }
+ }
+
+ if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ drm_handle_vblank(dev, 1)) {
+ if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
+ intel_prepare_page_flip(dev, 1);
+ intel_finish_page_flip(dev, 1);
+ flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+ }
+ }
+
+ iir = new_iir;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void i8xx_irq_uninstall(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ dev_priv->vblank_pipe = 0;
+
+ for_each_pipe(pipe) {
+ /* Clear enable bits; then clear status bits */
+ I915_WRITE(PIPESTAT(pipe), 0);
+ I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
+ }
+ I915_WRITE16(IMR, 0xffff);
+ I915_WRITE16(IER, 0x0);
+ I915_WRITE16(IIR, I915_READ16(IIR));
+}
+
void intel_irq_init(struct drm_device *dev)
{
dev->driver->get_vblank_counter = i915_get_vblank_counter;
@@ -2114,10 +2260,17 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->enable_vblank = ironlake_enable_vblank;
dev->driver->disable_vblank = ironlake_disable_vblank;
} else {
- dev->driver->irq_preinstall = i915_driver_irq_preinstall;
- dev->driver->irq_postinstall = i915_driver_irq_postinstall;
- dev->driver->irq_uninstall = i915_driver_irq_uninstall;
- dev->driver->irq_handler = i915_driver_irq_handler;
+ if (INTEL_INFO(dev)->gen == 2) {
+ dev->driver->irq_preinstall = i8xx_irq_preinstall;
+ dev->driver->irq_postinstall = i8xx_irq_postinstall;
+ dev->driver->irq_handler = i8xx_irq_handler;
+ dev->driver->irq_uninstall = i8xx_irq_uninstall;
+ } else {
+ dev->driver->irq_preinstall = i915_driver_irq_preinstall;
+ dev->driver->irq_postinstall = i915_driver_irq_postinstall;
+ dev->driver->irq_uninstall = i915_driver_irq_uninstall;
+ dev->driver->irq_handler = i915_driver_irq_handler;
+ }
dev->driver->enable_vblank = i915_enable_vblank;
dev->driver->disable_vblank = i915_disable_vblank;
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 19085c0..57a7363 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -689,16 +689,26 @@ static void
i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
dev_priv->irq_mask &= ~mask;
- I915_WRITE(IMR, dev_priv->irq_mask);
- POSTING_READ(IMR);
+ if (IS_GEN2(dev_priv->dev)) {
+ I915_WRITE16(IMR, dev_priv->irq_mask);
+ POSTING_READ16(IMR);
+ } else {
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ POSTING_READ(IMR);
+ }
}

static void
i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
dev_priv->irq_mask |= mask;
- I915_WRITE(IMR, dev_priv->irq_mask);
- POSTING_READ(IMR);
+ if (IS_GEN2(dev_priv->dev)) {
+ I915_WRITE16(IMR, dev_priv->irq_mask);
+ POSTING_READ16(IMR);
+ } else {
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ POSTING_READ(IMR);
+ }
}

static bool
--
1.7.10.4

"Sten Heinze" 08-26-2012 04:26 PM

Bug#655152: *ERROR* Prepared flip multiple times
 
Hi Jonathan,

Finally I got around to test this patch. While the system if fine for office work, cloning linux.git or compiling kernels takes hours.

> Please test the attached patch against a 3.2.y kernel, for example
> using the following instructions:

Done with testing, results below. These instructions were really good and easy to use, thanks for that!

> *3. configure, build, test:
>
> git checkout stable/linux-3.2.y
> cp /boot/config-$(uname -r) .config; # current configuration
> scripts/config --disable DEBUG_INFO
> make localmodconfig; # optional: minimize configuration
> make deb-pkg; # optionally with -j<num> for parallel build
> dpkg -i ../<name of package>; # as root
> reboot
> ...test test test ...

I compiled 3.2.28, and it reproduces the bug within the first minute after boot and the logs are full of the error message.

> *4. try the patch:
>
> cd linux
> git am -3sc /path/to/the/patch
> make deb-pkg; # maybe with -j4
> dpkg -i ../<name of package>; # as root
> reboot
> ... test test test ...

The patch fixes the problem. I've run more than 30 minutes without a single occurrence of the error message in the logs. Everything I tested seems to be still working, Graphics, Suspend, etc.

Sten


--
To UNSUBSCRIBE, email to debian-kernel-REQUEST@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org
Archive: 20120826162626.194540@gmx.net">http://lists.debian.org/20120826162626.194540@gmx.net


All times are GMT. The time now is 03:02 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.