aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-08 20:09:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-08 20:09:24 -0400
commite6890f6f3dc2d9024a08b1a149d9bd5208eea350 (patch)
tree8829fbb9f165ff37a37181bdf5cbbe92622bb5e6
parent7c8460db30dfd085ef3837c8fb02ecf2e718b983 (diff)
i915: disable interrupts before tearing down GEM state
Reinette Chatre reports a frozen system (with blinking keyboard LEDs) when switching from graphics mode to the text console, or when suspending (which does the same thing). With netconsole, the oops turned out to be BUG: unable to handle kernel NULL pointer dereference at 0000000000000084 IP: [<ffffffffa03ecaab>] i915_driver_irq_handler+0x26b/0xd20 [i915] and it's due to the i915_gem.c code doing drm_irq_uninstall() after having done i915_gem_idle(). And the i915_gem_idle() path will do i915_gem_idle() -> i915_gem_cleanup_ringbuffer() -> i915_gem_cleanup_hws() -> dev_priv->hw_status_page = NULL; but if an i915 interrupt comes in after this stage, it may want to access that hw_status_page, and gets the above NULL pointer dereference. And since the NULL pointer dereference happens from within an interrupt, and with the screen still in graphics mode, the common end result is simply a silently hung machine. Fix it by simply uninstalling the irq handler before idling rather than after. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=13819 Reported-and-tested-by: Reinette Chatre <reinette.chatre@intel.com> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c6
1 files changed, 1 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 7edb5b9d5792..80e5ba490dc2 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4232,15 +4232,11 @@ int
4232i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, 4232i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
4233 struct drm_file *file_priv) 4233 struct drm_file *file_priv)
4234{ 4234{
4235 int ret;
4236
4237 if (drm_core_check_feature(dev, DRIVER_MODESET)) 4235 if (drm_core_check_feature(dev, DRIVER_MODESET))
4238 return 0; 4236 return 0;
4239 4237
4240 ret = i915_gem_idle(dev);
4241 drm_irq_uninstall(dev); 4238 drm_irq_uninstall(dev);
4242 4239 return i915_gem_idle(dev);
4243 return ret;
4244} 4240}
4245 4241
4246void 4242void