diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-08-09 10:46:01 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-08-09 15:53:52 -0400 |
commit | 9270388e184fddb83e3b69c6b7f5b523c070e53d (patch) | |
tree | 10286bc3872461b729bd817c995190970aafcdb4 /drivers/gpu/drm/i915 | |
parent | 73edd18f610b6dd900cc3a180919dc643fff8513 (diff) |
drm/i915: fix up ilk drps/ips locking
We change the drps/ips sw/hw state from different callers: Our own irq
handler, the external intel-ips module and from process context. Most
of these callers don't take any lock at all.
Protect everything by making the mchdev_lock irqsave and grabbing it in
all relevant callsites. Note that we have to convert a few sleeps in the
drps enable/disable code to delays, but alas, I'm not volunteering to
restructure the code around a few work items.
For paranoia add a spin_locked assert to ironlake_set_drps, too.
v2: Move one access inside the lock protection. Caught by the
dev_priv->ips mass-rename ...
v3: Resolve rebase conflict.
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 83 |
2 files changed, 58 insertions, 37 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3e203da61c69..d15ea50f5854 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -296,14 +296,22 @@ static void i915_hotplug_work_func(struct work_struct *work) | |||
296 | drm_helper_hpd_irq_event(dev); | 296 | drm_helper_hpd_irq_event(dev); |
297 | } | 297 | } |
298 | 298 | ||
299 | /* defined intel_pm.c */ | ||
300 | extern spinlock_t mchdev_lock; | ||
301 | |||
299 | static void ironlake_handle_rps_change(struct drm_device *dev) | 302 | static void ironlake_handle_rps_change(struct drm_device *dev) |
300 | { | 303 | { |
301 | drm_i915_private_t *dev_priv = dev->dev_private; | 304 | drm_i915_private_t *dev_priv = dev->dev_private; |
302 | u32 busy_up, busy_down, max_avg, min_avg; | 305 | u32 busy_up, busy_down, max_avg, min_avg; |
303 | u8 new_delay = dev_priv->cur_delay; | 306 | u8 new_delay; |
307 | unsigned long flags; | ||
308 | |||
309 | spin_lock_irqsave(&mchdev_lock, flags); | ||
304 | 310 | ||
305 | I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); | 311 | I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); |
306 | 312 | ||
313 | new_delay = dev_priv->cur_delay; | ||
314 | |||
307 | I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); | 315 | I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG); |
308 | busy_up = I915_READ(RCPREVBSYTUPAVG); | 316 | busy_up = I915_READ(RCPREVBSYTUPAVG); |
309 | busy_down = I915_READ(RCPREVBSYTDNAVG); | 317 | busy_down = I915_READ(RCPREVBSYTDNAVG); |
@@ -326,6 +334,8 @@ static void ironlake_handle_rps_change(struct drm_device *dev) | |||
326 | if (ironlake_set_drps(dev, new_delay)) | 334 | if (ironlake_set_drps(dev, new_delay)) |
327 | dev_priv->cur_delay = new_delay; | 335 | dev_priv->cur_delay = new_delay; |
328 | 336 | ||
337 | spin_unlock_irqrestore(&mchdev_lock, flags); | ||
338 | |||
329 | return; | 339 | return; |
330 | } | 340 | } |
331 | 341 | ||
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 212b28e1b050..6d68a0599686 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
@@ -2160,11 +2160,28 @@ err_unref: | |||
2160 | return NULL; | 2160 | return NULL; |
2161 | } | 2161 | } |
2162 | 2162 | ||
2163 | /** | ||
2164 | * Lock protecting IPS related data structures | ||
2165 | * - i915_mch_dev | ||
2166 | * - dev_priv->max_delay | ||
2167 | * - dev_priv->min_delay | ||
2168 | * - dev_priv->fmax | ||
2169 | * - dev_priv->gpu_busy | ||
2170 | * - dev_priv->gfx_power | ||
2171 | */ | ||
2172 | DEFINE_SPINLOCK(mchdev_lock); | ||
2173 | |||
2174 | /* Global for IPS driver to get at the current i915 device. Protected by | ||
2175 | * mchdev_lock. */ | ||
2176 | static struct drm_i915_private *i915_mch_dev; | ||
2177 | |||
2163 | bool ironlake_set_drps(struct drm_device *dev, u8 val) | 2178 | bool ironlake_set_drps(struct drm_device *dev, u8 val) |
2164 | { | 2179 | { |
2165 | struct drm_i915_private *dev_priv = dev->dev_private; | 2180 | struct drm_i915_private *dev_priv = dev->dev_private; |
2166 | u16 rgvswctl; | 2181 | u16 rgvswctl; |
2167 | 2182 | ||
2183 | assert_spin_locked(&mchdev_lock); | ||
2184 | |||
2168 | rgvswctl = I915_READ16(MEMSWCTL); | 2185 | rgvswctl = I915_READ16(MEMSWCTL); |
2169 | if (rgvswctl & MEMCTL_CMD_STS) { | 2186 | if (rgvswctl & MEMCTL_CMD_STS) { |
2170 | DRM_DEBUG("gpu busy, RCS change rejected\n"); | 2187 | DRM_DEBUG("gpu busy, RCS change rejected\n"); |
@@ -2188,6 +2205,8 @@ static void ironlake_enable_drps(struct drm_device *dev) | |||
2188 | u32 rgvmodectl = I915_READ(MEMMODECTL); | 2205 | u32 rgvmodectl = I915_READ(MEMMODECTL); |
2189 | u8 fmax, fmin, fstart, vstart; | 2206 | u8 fmax, fmin, fstart, vstart; |
2190 | 2207 | ||
2208 | spin_lock_irq(&mchdev_lock); | ||
2209 | |||
2191 | /* Enable temp reporting */ | 2210 | /* Enable temp reporting */ |
2192 | I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); | 2211 | I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); |
2193 | I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); | 2212 | I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); |
@@ -2233,9 +2252,9 @@ static void ironlake_enable_drps(struct drm_device *dev) | |||
2233 | rgvmodectl |= MEMMODE_SWMODE_EN; | 2252 | rgvmodectl |= MEMMODE_SWMODE_EN; |
2234 | I915_WRITE(MEMMODECTL, rgvmodectl); | 2253 | I915_WRITE(MEMMODECTL, rgvmodectl); |
2235 | 2254 | ||
2236 | if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) | 2255 | if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) |
2237 | DRM_ERROR("stuck trying to change perf mode\n"); | 2256 | DRM_ERROR("stuck trying to change perf mode\n"); |
2238 | msleep(1); | 2257 | mdelay(1); |
2239 | 2258 | ||
2240 | ironlake_set_drps(dev, fstart); | 2259 | ironlake_set_drps(dev, fstart); |
2241 | 2260 | ||
@@ -2244,12 +2263,18 @@ static void ironlake_enable_drps(struct drm_device *dev) | |||
2244 | dev_priv->last_time1 = jiffies_to_msecs(jiffies); | 2263 | dev_priv->last_time1 = jiffies_to_msecs(jiffies); |
2245 | dev_priv->last_count2 = I915_READ(0x112f4); | 2264 | dev_priv->last_count2 = I915_READ(0x112f4); |
2246 | getrawmonotonic(&dev_priv->last_time2); | 2265 | getrawmonotonic(&dev_priv->last_time2); |
2266 | |||
2267 | spin_unlock_irq(&mchdev_lock); | ||
2247 | } | 2268 | } |
2248 | 2269 | ||
2249 | static void ironlake_disable_drps(struct drm_device *dev) | 2270 | static void ironlake_disable_drps(struct drm_device *dev) |
2250 | { | 2271 | { |
2251 | struct drm_i915_private *dev_priv = dev->dev_private; | 2272 | struct drm_i915_private *dev_priv = dev->dev_private; |
2252 | u16 rgvswctl = I915_READ16(MEMSWCTL); | 2273 | u16 rgvswctl; |
2274 | |||
2275 | spin_lock_irq(&mchdev_lock); | ||
2276 | |||
2277 | rgvswctl = I915_READ16(MEMSWCTL); | ||
2253 | 2278 | ||
2254 | /* Ack interrupts, disable EFC interrupt */ | 2279 | /* Ack interrupts, disable EFC interrupt */ |
2255 | I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); | 2280 | I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); |
@@ -2260,11 +2285,12 @@ static void ironlake_disable_drps(struct drm_device *dev) | |||
2260 | 2285 | ||
2261 | /* Go back to the starting frequency */ | 2286 | /* Go back to the starting frequency */ |
2262 | ironlake_set_drps(dev, dev_priv->fstart); | 2287 | ironlake_set_drps(dev, dev_priv->fstart); |
2263 | msleep(1); | 2288 | mdelay(1); |
2264 | rgvswctl |= MEMCTL_CMD_STS; | 2289 | rgvswctl |= MEMCTL_CMD_STS; |
2265 | I915_WRITE(MEMSWCTL, rgvswctl); | 2290 | I915_WRITE(MEMSWCTL, rgvswctl); |
2266 | msleep(1); | 2291 | mdelay(1); |
2267 | 2292 | ||
2293 | spin_unlock_irq(&mchdev_lock); | ||
2268 | } | 2294 | } |
2269 | 2295 | ||
2270 | /* There's a funny hw issue where the hw returns all 0 when reading from | 2296 | /* There's a funny hw issue where the hw returns all 0 when reading from |
@@ -2713,21 +2739,6 @@ static const struct cparams { | |||
2713 | { 0, 800, 231, 23784 }, | 2739 | { 0, 800, 231, 23784 }, |
2714 | }; | 2740 | }; |
2715 | 2741 | ||
2716 | /** | ||
2717 | * Lock protecting IPS related data structures | ||
2718 | * - i915_mch_dev | ||
2719 | * - dev_priv->max_delay | ||
2720 | * - dev_priv->min_delay | ||
2721 | * - dev_priv->fmax | ||
2722 | * - dev_priv->gpu_busy | ||
2723 | * - dev_priv->gfx_power | ||
2724 | */ | ||
2725 | static DEFINE_SPINLOCK(mchdev_lock); | ||
2726 | |||
2727 | /* Global for IPS driver to get at the current i915 device. Protected by | ||
2728 | * mchdev_lock. */ | ||
2729 | static struct drm_i915_private *i915_mch_dev; | ||
2730 | |||
2731 | unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) | 2742 | unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) |
2732 | { | 2743 | { |
2733 | u64 total_count, diff, ret; | 2744 | u64 total_count, diff, ret; |
@@ -2978,11 +2989,11 @@ void i915_update_gfx_val(struct drm_i915_private *dev_priv) | |||
2978 | if (dev_priv->info->gen != 5) | 2989 | if (dev_priv->info->gen != 5) |
2979 | return; | 2990 | return; |
2980 | 2991 | ||
2981 | spin_lock(&mchdev_lock); | 2992 | spin_lock_irq(&mchdev_lock); |
2982 | 2993 | ||
2983 | __i915_update_gfx_val(dev_priv); | 2994 | __i915_update_gfx_val(dev_priv); |
2984 | 2995 | ||
2985 | spin_unlock(&mchdev_lock); | 2996 | spin_unlock_irq(&mchdev_lock); |
2986 | } | 2997 | } |
2987 | 2998 | ||
2988 | unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) | 2999 | unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) |
@@ -3033,7 +3044,7 @@ unsigned long i915_read_mch_val(void) | |||
3033 | struct drm_i915_private *dev_priv; | 3044 | struct drm_i915_private *dev_priv; |
3034 | unsigned long chipset_val, graphics_val, ret = 0; | 3045 | unsigned long chipset_val, graphics_val, ret = 0; |
3035 | 3046 | ||
3036 | spin_lock(&mchdev_lock); | 3047 | spin_lock_irq(&mchdev_lock); |
3037 | if (!i915_mch_dev) | 3048 | if (!i915_mch_dev) |
3038 | goto out_unlock; | 3049 | goto out_unlock; |
3039 | dev_priv = i915_mch_dev; | 3050 | dev_priv = i915_mch_dev; |
@@ -3044,7 +3055,7 @@ unsigned long i915_read_mch_val(void) | |||
3044 | ret = chipset_val + graphics_val; | 3055 | ret = chipset_val + graphics_val; |
3045 | 3056 | ||
3046 | out_unlock: | 3057 | out_unlock: |
3047 | spin_unlock(&mchdev_lock); | 3058 | spin_unlock_irq(&mchdev_lock); |
3048 | 3059 | ||
3049 | return ret; | 3060 | return ret; |
3050 | } | 3061 | } |
@@ -3060,7 +3071,7 @@ bool i915_gpu_raise(void) | |||
3060 | struct drm_i915_private *dev_priv; | 3071 | struct drm_i915_private *dev_priv; |
3061 | bool ret = true; | 3072 | bool ret = true; |
3062 | 3073 | ||
3063 | spin_lock(&mchdev_lock); | 3074 | spin_lock_irq(&mchdev_lock); |
3064 | if (!i915_mch_dev) { | 3075 | if (!i915_mch_dev) { |
3065 | ret = false; | 3076 | ret = false; |
3066 | goto out_unlock; | 3077 | goto out_unlock; |
@@ -3071,7 +3082,7 @@ bool i915_gpu_raise(void) | |||
3071 | dev_priv->max_delay--; | 3082 | dev_priv->max_delay--; |
3072 | 3083 | ||
3073 | out_unlock: | 3084 | out_unlock: |
3074 | spin_unlock(&mchdev_lock); | 3085 | spin_unlock_irq(&mchdev_lock); |
3075 | 3086 | ||
3076 | return ret; | 3087 | return ret; |
3077 | } | 3088 | } |
@@ -3088,7 +3099,7 @@ bool i915_gpu_lower(void) | |||
3088 | struct drm_i915_private *dev_priv; | 3099 | struct drm_i915_private *dev_priv; |
3089 | bool ret = true; | 3100 | bool ret = true; |
3090 | 3101 | ||
3091 | spin_lock(&mchdev_lock); | 3102 | spin_lock_irq(&mchdev_lock); |
3092 | if (!i915_mch_dev) { | 3103 | if (!i915_mch_dev) { |
3093 | ret = false; | 3104 | ret = false; |
3094 | goto out_unlock; | 3105 | goto out_unlock; |
@@ -3099,7 +3110,7 @@ bool i915_gpu_lower(void) | |||
3099 | dev_priv->max_delay++; | 3110 | dev_priv->max_delay++; |
3100 | 3111 | ||
3101 | out_unlock: | 3112 | out_unlock: |
3102 | spin_unlock(&mchdev_lock); | 3113 | spin_unlock_irq(&mchdev_lock); |
3103 | 3114 | ||
3104 | return ret; | 3115 | return ret; |
3105 | } | 3116 | } |
@@ -3117,7 +3128,7 @@ bool i915_gpu_busy(void) | |||
3117 | bool ret = false; | 3128 | bool ret = false; |
3118 | int i; | 3129 | int i; |
3119 | 3130 | ||
3120 | spin_lock(&mchdev_lock); | 3131 | spin_lock_irq(&mchdev_lock); |
3121 | if (!i915_mch_dev) | 3132 | if (!i915_mch_dev) |
3122 | goto out_unlock; | 3133 | goto out_unlock; |
3123 | dev_priv = i915_mch_dev; | 3134 | dev_priv = i915_mch_dev; |
@@ -3126,7 +3137,7 @@ bool i915_gpu_busy(void) | |||
3126 | ret |= !list_empty(&ring->request_list); | 3137 | ret |= !list_empty(&ring->request_list); |
3127 | 3138 | ||
3128 | out_unlock: | 3139 | out_unlock: |
3129 | spin_unlock(&mchdev_lock); | 3140 | spin_unlock_irq(&mchdev_lock); |
3130 | 3141 | ||
3131 | return ret; | 3142 | return ret; |
3132 | } | 3143 | } |
@@ -3143,7 +3154,7 @@ bool i915_gpu_turbo_disable(void) | |||
3143 | struct drm_i915_private *dev_priv; | 3154 | struct drm_i915_private *dev_priv; |
3144 | bool ret = true; | 3155 | bool ret = true; |
3145 | 3156 | ||
3146 | spin_lock(&mchdev_lock); | 3157 | spin_lock_irq(&mchdev_lock); |
3147 | if (!i915_mch_dev) { | 3158 | if (!i915_mch_dev) { |
3148 | ret = false; | 3159 | ret = false; |
3149 | goto out_unlock; | 3160 | goto out_unlock; |
@@ -3156,7 +3167,7 @@ bool i915_gpu_turbo_disable(void) | |||
3156 | ret = false; | 3167 | ret = false; |
3157 | 3168 | ||
3158 | out_unlock: | 3169 | out_unlock: |
3159 | spin_unlock(&mchdev_lock); | 3170 | spin_unlock_irq(&mchdev_lock); |
3160 | 3171 | ||
3161 | return ret; | 3172 | return ret; |
3162 | } | 3173 | } |
@@ -3186,18 +3197,18 @@ void intel_gpu_ips_init(struct drm_i915_private *dev_priv) | |||
3186 | { | 3197 | { |
3187 | /* We only register the i915 ips part with intel-ips once everything is | 3198 | /* We only register the i915 ips part with intel-ips once everything is |
3188 | * set up, to avoid intel-ips sneaking in and reading bogus values. */ | 3199 | * set up, to avoid intel-ips sneaking in and reading bogus values. */ |
3189 | spin_lock(&mchdev_lock); | 3200 | spin_lock_irq(&mchdev_lock); |
3190 | i915_mch_dev = dev_priv; | 3201 | i915_mch_dev = dev_priv; |
3191 | spin_unlock(&mchdev_lock); | 3202 | spin_unlock_irq(&mchdev_lock); |
3192 | 3203 | ||
3193 | ips_ping_for_i915_load(); | 3204 | ips_ping_for_i915_load(); |
3194 | } | 3205 | } |
3195 | 3206 | ||
3196 | void intel_gpu_ips_teardown(void) | 3207 | void intel_gpu_ips_teardown(void) |
3197 | { | 3208 | { |
3198 | spin_lock(&mchdev_lock); | 3209 | spin_lock_irq(&mchdev_lock); |
3199 | i915_mch_dev = NULL; | 3210 | i915_mch_dev = NULL; |
3200 | spin_unlock(&mchdev_lock); | 3211 | spin_unlock_irq(&mchdev_lock); |
3201 | } | 3212 | } |
3202 | static void intel_init_emon(struct drm_device *dev) | 3213 | static void intel_init_emon(struct drm_device *dev) |
3203 | { | 3214 | { |