aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2011-12-14 07:57:03 -0500
committerKeith Packard <keithp@keithp.com>2012-01-19 14:51:31 -0500
commit9f1f46a45a681d357d1ceedecec3671a5ae957f4 (patch)
treefbb1ccb3dc2afded75087e2d187a5160e356849f /drivers
parent8109021313c7a3d8947677391ce6ab9cd0bb1d28 (diff)
drm/i915: protect force_wake_(get|put) with the gt_lock
The problem this patch solves is that the forcewake accounting necessary for register reads is protected by dev->struct_mutex. But the hangcheck and error_capture code need to access registers without grabbing this mutex because we hold it while waiting for the gpu. So a new lock is required. Because currently the error_state capture is called from the error irq handler and the hangcheck code runs from a timer, it needs to be an irqsafe spinlock (note that the registers used by the irq handler (neglecting the error handling part) only uses registers that don't need the forcewake dance). We could tune this down to a normal spinlock when we rework the error_state capture and hangcheck code to run from a workqueue. But we don't have any read in a fastpath that needs forcewake, so I've decided to not care much about overhead. This prevents tests/gem_hangcheck_forcewake from i-g-t from killing my snb on recent kernels - something must have slightly changed the timings. On previous kernels it only trigger a WARN about the broken locking. v2: Drop the previous patch for the register writes. v3: Improve the commit message per Chris Wilson's suggestions. Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c8
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c18
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h10
4 files changed, 26 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f8b8ed22b4d..a017b989b1a 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1398,9 +1398,13 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
1398 struct drm_info_node *node = (struct drm_info_node *) m->private; 1398 struct drm_info_node *node = (struct drm_info_node *) m->private;
1399 struct drm_device *dev = node->minor->dev; 1399 struct drm_device *dev = node->minor->dev;
1400 struct drm_i915_private *dev_priv = dev->dev_private; 1400 struct drm_i915_private *dev_priv = dev->dev_private;
1401 unsigned forcewake_count;
1401 1402
1402 seq_printf(m, "forcewake count = %d\n", 1403 spin_lock_irq(&dev_priv->gt_lock);
1403 atomic_read(&dev_priv->forcewake_count)); 1404 forcewake_count = dev_priv->forcewake_count;
1405 spin_unlock_irq(&dev_priv->gt_lock);
1406
1407 seq_printf(m, "forcewake count = %u\n", forcewake_count);
1404 1408
1405 return 0; 1409 return 0;
1406} 1410}
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 5f4d5893e98..ddfe3d902b2 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -2045,6 +2045,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
2045 if (!IS_I945G(dev) && !IS_I945GM(dev)) 2045 if (!IS_I945G(dev) && !IS_I945GM(dev))
2046 pci_enable_msi(dev->pdev); 2046 pci_enable_msi(dev->pdev);
2047 2047
2048 spin_lock_init(&dev_priv->gt_lock);
2048 spin_lock_init(&dev_priv->irq_lock); 2049 spin_lock_init(&dev_priv->irq_lock);
2049 spin_lock_init(&dev_priv->error_lock); 2050 spin_lock_init(&dev_priv->error_lock);
2050 spin_lock_init(&dev_priv->rps_lock); 2051 spin_lock_init(&dev_priv->rps_lock);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 46c36f5cafb..bdf6a1b3622 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -368,11 +368,12 @@ void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
368 */ 368 */
369void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) 369void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
370{ 370{
371 WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); 371 unsigned long irqflags;
372 372
373 /* Forcewake is atomic in case we get in here without the lock */ 373 spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
374 if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) 374 if (dev_priv->forcewake_count++ == 0)
375 dev_priv->display.force_wake_get(dev_priv); 375 dev_priv->display.force_wake_get(dev_priv);
376 spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
376} 377}
377 378
378void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) 379void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
@@ -392,10 +393,12 @@ void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
392 */ 393 */
393void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) 394void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
394{ 395{
395 WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); 396 unsigned long irqflags;
396 397
397 if (atomic_dec_and_test(&dev_priv->forcewake_count)) 398 spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
399 if (--dev_priv->forcewake_count == 0)
398 dev_priv->display.force_wake_put(dev_priv); 400 dev_priv->display.force_wake_put(dev_priv);
401 spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
399} 402}
400 403
401void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) 404void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
@@ -626,6 +629,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
626 * need to 629 * need to
627 */ 630 */
628 bool need_display = true; 631 bool need_display = true;
632 unsigned long irqflags;
629 int ret; 633 int ret;
630 634
631 if (!i915_try_reset) 635 if (!i915_try_reset)
@@ -644,8 +648,10 @@ int i915_reset(struct drm_device *dev, u8 flags)
644 case 6: 648 case 6:
645 ret = gen6_do_reset(dev, flags); 649 ret = gen6_do_reset(dev, flags);
646 /* If reset with a user forcewake, try to restore */ 650 /* If reset with a user forcewake, try to restore */
647 if (atomic_read(&dev_priv->forcewake_count)) 651 spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
652 if (dev_priv->forcewake_count)
648 dev_priv->display.force_wake_get(dev_priv); 653 dev_priv->display.force_wake_get(dev_priv);
654 spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
649 break; 655 break;
650 case 5: 656 case 5:
651 ret = ironlake_do_reset(dev, flags); 657 ret = ironlake_do_reset(dev, flags);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 602bc80baab..9689ca38b2b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -288,7 +288,13 @@ typedef struct drm_i915_private {
288 int relative_constants_mode; 288 int relative_constants_mode;
289 289
290 void __iomem *regs; 290 void __iomem *regs;
291 u32 gt_fifo_count; 291 /** gt_fifo_count and the subsequent register write are synchronized
292 * with dev->struct_mutex. */
293 unsigned gt_fifo_count;
294 /** forcewake_count is protected by gt_lock */
295 unsigned forcewake_count;
296 /** gt_lock is also taken in irq contexts. */
297 struct spinlock gt_lock;
292 298
293 struct intel_gmbus { 299 struct intel_gmbus {
294 struct i2c_adapter adapter; 300 struct i2c_adapter adapter;
@@ -741,8 +747,6 @@ typedef struct drm_i915_private {
741 747
742 struct drm_property *broadcast_rgb_property; 748 struct drm_property *broadcast_rgb_property;
743 struct drm_property *force_audio_property; 749 struct drm_property *force_audio_property;
744
745 atomic_t forcewake_count;
746} drm_i915_private_t; 750} drm_i915_private_t;
747 751
748enum i915_cache_level { 752enum i915_cache_level {