diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-08 20:09:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-08 20:09:24 -0400 |
commit | e6890f6f3dc2d9024a08b1a149d9bd5208eea350 (patch) | |
tree | 8829fbb9f165ff37a37181bdf5cbbe92622bb5e6 | |
parent | 7c8460db30dfd085ef3837c8fb02ecf2e718b983 (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.c | 6 |
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 | |||
4232 | i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, | 4232 | i915_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 | ||
4246 | void | 4242 | void |