]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/meta-ti-glsdk.git/blob - recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.6/0046-drm-i915-protect-force_wake_-get-put-with-the-gt_loc.patch
linux-ti335x-psp 3.2: update to v3.2.11
[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-ti33x-psp-3.2 / 3.2.6 / 0046-drm-i915-protect-force_wake_-get-put-with-the-gt_loc.patch
1 From 929430116c4a6355aafbce7cef4bbea15a8bdd9e Mon Sep 17 00:00:00 2001
2 From: Daniel Vetter <daniel.vetter@ffwll.ch>
3 Date: Wed, 14 Dec 2011 13:57:03 +0100
4 Subject: [PATCH 46/87] drm/i915: protect force_wake_(get|put) with the
5  gt_lock
7 commit 9f1f46a45a681d357d1ceedecec3671a5ae957f4 upstream.
9 The problem this patch solves is that the forcewake accounting
10 necessary for register reads is protected by dev->struct_mutex. But the
11 hangcheck and error_capture code need to access registers without
12 grabbing this mutex because we hold it while waiting for the gpu.
13 So a new lock is required. Because currently the error_state capture
14 is called from the error irq handler and the hangcheck code runs from
15 a timer, it needs to be an irqsafe spinlock (note that the registers
16 used by the irq handler (neglecting the error handling part) only uses
17 registers that don't need the forcewake dance).
19 We could tune this down to a normal spinlock when we rework the
20 error_state capture and hangcheck code to run from a workqueue.  But
21 we don't have any read in a fastpath that needs forcewake, so I've
22 decided to not care much about overhead.
24 This prevents tests/gem_hangcheck_forcewake from i-g-t from killing my
25 snb on recent kernels - something must have slightly changed the
26 timings. On previous kernels it only trigger a WARN about the broken
27 locking.
29 v2: Drop the previous patch for the register writes.
31 v3: Improve the commit message per Chris Wilson's suggestions.
33 Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
34 Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
35 Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
36 Signed-off-by: Keith Packard <keithp@keithp.com>
37 Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
38 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
39 ---
40  drivers/gpu/drm/i915/i915_debugfs.c |    8 ++++++--
41  drivers/gpu/drm/i915/i915_dma.c     |    1 +
42  drivers/gpu/drm/i915/i915_drv.c     |   18 ++++++++++++------
43  drivers/gpu/drm/i915/i915_drv.h     |   10 +++++++---
44  4 files changed, 26 insertions(+), 11 deletions(-)
46 diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
47 index 004b048..b2e3c97 100644
48 --- a/drivers/gpu/drm/i915/i915_debugfs.c
49 +++ b/drivers/gpu/drm/i915/i915_debugfs.c
50 @@ -1314,9 +1314,13 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
51         struct drm_info_node *node = (struct drm_info_node *) m->private;
52         struct drm_device *dev = node->minor->dev;
53         struct drm_i915_private *dev_priv = dev->dev_private;
54 +       unsigned forcewake_count;
55  
56 -       seq_printf(m, "forcewake count = %d\n",
57 -                  atomic_read(&dev_priv->forcewake_count));
58 +       spin_lock_irq(&dev_priv->gt_lock);
59 +       forcewake_count = dev_priv->forcewake_count;
60 +       spin_unlock_irq(&dev_priv->gt_lock);
61 +
62 +       seq_printf(m, "forcewake count = %u\n", forcewake_count);
63  
64         return 0;
65  }
66 diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
67 index a9ae374..c4da951 100644
68 --- a/drivers/gpu/drm/i915/i915_dma.c
69 +++ b/drivers/gpu/drm/i915/i915_dma.c
70 @@ -2042,6 +2042,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
71         if (!IS_I945G(dev) && !IS_I945GM(dev))
72                 pci_enable_msi(dev->pdev);
73  
74 +       spin_lock_init(&dev_priv->gt_lock);
75         spin_lock_init(&dev_priv->irq_lock);
76         spin_lock_init(&dev_priv->error_lock);
77         spin_lock_init(&dev_priv->rps_lock);
78 diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
79 index d7c9d99..e2d85a9 100644
80 --- a/drivers/gpu/drm/i915/i915_drv.c
81 +++ b/drivers/gpu/drm/i915/i915_drv.c
82 @@ -368,11 +368,12 @@ void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
83   */
84  void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
85  {
86 -       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
87 +       unsigned long irqflags;
88  
89 -       /* Forcewake is atomic in case we get in here without the lock */
90 -       if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
91 +       spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
92 +       if (dev_priv->forcewake_count++ == 0)
93                 dev_priv->display.force_wake_get(dev_priv);
94 +       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
95  }
96  
97  void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
98 @@ -392,10 +393,12 @@ void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
99   */
100  void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
101  {
102 -       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
103 +       unsigned long irqflags;
104  
105 -       if (atomic_dec_and_test(&dev_priv->forcewake_count))
106 +       spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
107 +       if (--dev_priv->forcewake_count == 0)
108                 dev_priv->display.force_wake_put(dev_priv);
109 +       spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
110  }
111  
112  void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
113 @@ -626,6 +629,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
114          * need to
115          */
116         bool need_display = true;
117 +       unsigned long irqflags;
118         int ret;
119  
120         if (!i915_try_reset)
121 @@ -644,8 +648,10 @@ int i915_reset(struct drm_device *dev, u8 flags)
122         case 6:
123                 ret = gen6_do_reset(dev, flags);
124                 /* If reset with a user forcewake, try to restore */
125 -               if (atomic_read(&dev_priv->forcewake_count))
126 +               spin_lock_irqsave(&dev_priv->gt_lock, irqflags);
127 +               if (dev_priv->forcewake_count)
128                         dev_priv->display.force_wake_get(dev_priv);
129 +               spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags);
130                 break;
131         case 5:
132                 ret = ironlake_do_reset(dev, flags);
133 diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
134 index 505af3f..ae294a0 100644
135 --- a/drivers/gpu/drm/i915/i915_drv.h
136 +++ b/drivers/gpu/drm/i915/i915_drv.h
137 @@ -286,7 +286,13 @@ typedef struct drm_i915_private {
138         int relative_constants_mode;
139  
140         void __iomem *regs;
141 -       u32 gt_fifo_count;
142 +       /** gt_fifo_count and the subsequent register write are synchronized
143 +        * with dev->struct_mutex. */
144 +       unsigned gt_fifo_count;
145 +       /** forcewake_count is protected by gt_lock */
146 +       unsigned forcewake_count;
147 +       /** gt_lock is also taken in irq contexts. */
148 +       struct spinlock gt_lock;
149  
150         struct intel_gmbus {
151                 struct i2c_adapter adapter;
152 @@ -738,8 +744,6 @@ typedef struct drm_i915_private {
153  
154         struct drm_property *broadcast_rgb_property;
155         struct drm_property *force_audio_property;
157 -       atomic_t forcewake_count;
158  } drm_i915_private_t;
159  
160  enum i915_cache_level {
161 -- 
162 1.7.9.4