diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_runtime_pm.c | 97 |
1 files changed, 79 insertions, 18 deletions
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 08f809371bbd..c29577d7a35a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c | |||
@@ -94,7 +94,7 @@ static void init_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | |||
94 | spin_lock_init(&rpm->debug.lock); | 94 | spin_lock_init(&rpm->debug.lock); |
95 | } | 95 | } |
96 | 96 | ||
97 | static noinline void | 97 | static noinline depot_stack_handle_t |
98 | track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | 98 | track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) |
99 | { | 99 | { |
100 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | 100 | struct i915_runtime_pm *rpm = &i915->runtime_pm; |
@@ -105,11 +105,11 @@ track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | |||
105 | assert_rpm_wakelock_held(i915); | 105 | assert_rpm_wakelock_held(i915); |
106 | 106 | ||
107 | if (!HAS_RUNTIME_PM(i915)) | 107 | if (!HAS_RUNTIME_PM(i915)) |
108 | return; | 108 | return -1; |
109 | 109 | ||
110 | stack = __save_depot_stack(); | 110 | stack = __save_depot_stack(); |
111 | if (!stack) | 111 | if (!stack) |
112 | return; | 112 | return -1; |
113 | 113 | ||
114 | spin_lock_irqsave(&rpm->debug.lock, flags); | 114 | spin_lock_irqsave(&rpm->debug.lock, flags); |
115 | 115 | ||
@@ -122,9 +122,57 @@ track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | |||
122 | if (stacks) { | 122 | if (stacks) { |
123 | stacks[rpm->debug.count++] = stack; | 123 | stacks[rpm->debug.count++] = stack; |
124 | rpm->debug.owners = stacks; | 124 | rpm->debug.owners = stacks; |
125 | } else { | ||
126 | stack = -1; | ||
125 | } | 127 | } |
126 | 128 | ||
127 | spin_unlock_irqrestore(&rpm->debug.lock, flags); | 129 | spin_unlock_irqrestore(&rpm->debug.lock, flags); |
130 | |||
131 | return stack; | ||
132 | } | ||
133 | |||
134 | static void cancel_intel_runtime_pm_wakeref(struct drm_i915_private *i915, | ||
135 | depot_stack_handle_t stack) | ||
136 | { | ||
137 | struct i915_runtime_pm *rpm = &i915->runtime_pm; | ||
138 | unsigned long flags, n; | ||
139 | bool found = false; | ||
140 | |||
141 | if (unlikely(stack == -1)) | ||
142 | return; | ||
143 | |||
144 | spin_lock_irqsave(&rpm->debug.lock, flags); | ||
145 | for (n = rpm->debug.count; n--; ) { | ||
146 | if (rpm->debug.owners[n] == stack) { | ||
147 | memmove(rpm->debug.owners + n, | ||
148 | rpm->debug.owners + n + 1, | ||
149 | (--rpm->debug.count - n) * sizeof(stack)); | ||
150 | found = true; | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | spin_unlock_irqrestore(&rpm->debug.lock, flags); | ||
155 | |||
156 | if (WARN(!found, | ||
157 | "Unmatched wakeref (tracking %lu), count %u\n", | ||
158 | rpm->debug.count, atomic_read(&rpm->wakeref_count))) { | ||
159 | char *buf; | ||
160 | |||
161 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
162 | if (!buf) | ||
163 | return; | ||
164 | |||
165 | __print_depot_stack(stack, buf, PAGE_SIZE, 2); | ||
166 | DRM_DEBUG_DRIVER("wakeref %x from\n%s", stack, buf); | ||
167 | |||
168 | stack = READ_ONCE(rpm->debug.last_release); | ||
169 | if (stack) { | ||
170 | __print_depot_stack(stack, buf, PAGE_SIZE, 2); | ||
171 | DRM_DEBUG_DRIVER("wakeref last released at\n%s", buf); | ||
172 | } | ||
173 | |||
174 | kfree(buf); | ||
175 | } | ||
128 | } | 176 | } |
129 | 177 | ||
130 | static int cmphandle(const void *_a, const void *_b) | 178 | static int cmphandle(const void *_a, const void *_b) |
@@ -249,10 +297,12 @@ static void init_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | |||
249 | { | 297 | { |
250 | } | 298 | } |
251 | 299 | ||
252 | static void track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | 300 | static depot_stack_handle_t |
301 | track_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | ||
253 | { | 302 | { |
254 | atomic_inc(&i915->runtime_pm.wakeref_count); | 303 | atomic_inc(&i915->runtime_pm.wakeref_count); |
255 | assert_rpm_wakelock_held(i915); | 304 | assert_rpm_wakelock_held(i915); |
305 | return -1; | ||
256 | } | 306 | } |
257 | 307 | ||
258 | static void untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915) | 308 | static void untrack_intel_runtime_pm_wakeref(struct drm_i915_private *i915) |
@@ -1852,7 +1902,7 @@ bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv, | |||
1852 | mutex_unlock(&power_domains->lock); | 1902 | mutex_unlock(&power_domains->lock); |
1853 | 1903 | ||
1854 | if (!is_enabled) | 1904 | if (!is_enabled) |
1855 | intel_runtime_pm_put(dev_priv); | 1905 | intel_runtime_pm_put_unchecked(dev_priv); |
1856 | 1906 | ||
1857 | return is_enabled; | 1907 | return is_enabled; |
1858 | } | 1908 | } |
@@ -1886,7 +1936,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, | |||
1886 | 1936 | ||
1887 | mutex_unlock(&power_domains->lock); | 1937 | mutex_unlock(&power_domains->lock); |
1888 | 1938 | ||
1889 | intel_runtime_pm_put(dev_priv); | 1939 | intel_runtime_pm_put_unchecked(dev_priv); |
1890 | } | 1940 | } |
1891 | 1941 | ||
1892 | #define I830_PIPES_POWER_DOMAINS ( \ | 1942 | #define I830_PIPES_POWER_DOMAINS ( \ |
@@ -3994,7 +4044,7 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume) | |||
3994 | void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv) | 4044 | void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv) |
3995 | { | 4045 | { |
3996 | /* Keep the power well enabled, but cancel its rpm wakeref. */ | 4046 | /* Keep the power well enabled, but cancel its rpm wakeref. */ |
3997 | intel_runtime_pm_put(dev_priv); | 4047 | intel_runtime_pm_put_unchecked(dev_priv); |
3998 | 4048 | ||
3999 | /* Remove the refcount we took to keep power well support disabled. */ | 4049 | /* Remove the refcount we took to keep power well support disabled. */ |
4000 | if (!i915_modparams.disable_power_well) | 4050 | if (!i915_modparams.disable_power_well) |
@@ -4207,8 +4257,10 @@ static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) | |||
4207 | * | 4257 | * |
4208 | * Any runtime pm reference obtained by this function must have a symmetric | 4258 | * Any runtime pm reference obtained by this function must have a symmetric |
4209 | * call to intel_runtime_pm_put() to release the reference again. | 4259 | * call to intel_runtime_pm_put() to release the reference again. |
4260 | * | ||
4261 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put() | ||
4210 | */ | 4262 | */ |
4211 | void intel_runtime_pm_get(struct drm_i915_private *i915) | 4263 | intel_wakeref_t intel_runtime_pm_get(struct drm_i915_private *i915) |
4212 | { | 4264 | { |
4213 | struct pci_dev *pdev = i915->drm.pdev; | 4265 | struct pci_dev *pdev = i915->drm.pdev; |
4214 | struct device *kdev = &pdev->dev; | 4266 | struct device *kdev = &pdev->dev; |
@@ -4217,7 +4269,7 @@ void intel_runtime_pm_get(struct drm_i915_private *i915) | |||
4217 | ret = pm_runtime_get_sync(kdev); | 4269 | ret = pm_runtime_get_sync(kdev); |
4218 | WARN_ONCE(ret < 0, "pm_runtime_get_sync() failed: %d\n", ret); | 4270 | WARN_ONCE(ret < 0, "pm_runtime_get_sync() failed: %d\n", ret); |
4219 | 4271 | ||
4220 | track_intel_runtime_pm_wakeref(i915); | 4272 | return track_intel_runtime_pm_wakeref(i915); |
4221 | } | 4273 | } |
4222 | 4274 | ||
4223 | /** | 4275 | /** |
@@ -4231,9 +4283,10 @@ void intel_runtime_pm_get(struct drm_i915_private *i915) | |||
4231 | * Any runtime pm reference obtained by this function must have a symmetric | 4283 | * Any runtime pm reference obtained by this function must have a symmetric |
4232 | * call to intel_runtime_pm_put() to release the reference again. | 4284 | * call to intel_runtime_pm_put() to release the reference again. |
4233 | * | 4285 | * |
4234 | * Returns: True if the wakeref was acquired, or False otherwise. | 4286 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put(), evaluates |
4287 | * as True if the wakeref was acquired, or False otherwise. | ||
4235 | */ | 4288 | */ |
4236 | bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *i915) | 4289 | intel_wakeref_t intel_runtime_pm_get_if_in_use(struct drm_i915_private *i915) |
4237 | { | 4290 | { |
4238 | if (IS_ENABLED(CONFIG_PM)) { | 4291 | if (IS_ENABLED(CONFIG_PM)) { |
4239 | struct pci_dev *pdev = i915->drm.pdev; | 4292 | struct pci_dev *pdev = i915->drm.pdev; |
@@ -4246,12 +4299,10 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *i915) | |||
4246 | * atm to the late/early system suspend/resume handlers. | 4299 | * atm to the late/early system suspend/resume handlers. |
4247 | */ | 4300 | */ |
4248 | if (pm_runtime_get_if_in_use(kdev) <= 0) | 4301 | if (pm_runtime_get_if_in_use(kdev) <= 0) |
4249 | return false; | 4302 | return 0; |
4250 | } | 4303 | } |
4251 | 4304 | ||
4252 | track_intel_runtime_pm_wakeref(i915); | 4305 | return track_intel_runtime_pm_wakeref(i915); |
4253 | |||
4254 | return true; | ||
4255 | } | 4306 | } |
4256 | 4307 | ||
4257 | /** | 4308 | /** |
@@ -4270,8 +4321,10 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *i915) | |||
4270 | * | 4321 | * |
4271 | * Any runtime pm reference obtained by this function must have a symmetric | 4322 | * Any runtime pm reference obtained by this function must have a symmetric |
4272 | * call to intel_runtime_pm_put() to release the reference again. | 4323 | * call to intel_runtime_pm_put() to release the reference again. |
4324 | * | ||
4325 | * Returns: the wakeref cookie to pass to intel_runtime_pm_put() | ||
4273 | */ | 4326 | */ |
4274 | void intel_runtime_pm_get_noresume(struct drm_i915_private *i915) | 4327 | intel_wakeref_t intel_runtime_pm_get_noresume(struct drm_i915_private *i915) |
4275 | { | 4328 | { |
4276 | struct pci_dev *pdev = i915->drm.pdev; | 4329 | struct pci_dev *pdev = i915->drm.pdev; |
4277 | struct device *kdev = &pdev->dev; | 4330 | struct device *kdev = &pdev->dev; |
@@ -4279,7 +4332,7 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *i915) | |||
4279 | assert_rpm_wakelock_held(i915); | 4332 | assert_rpm_wakelock_held(i915); |
4280 | pm_runtime_get_noresume(kdev); | 4333 | pm_runtime_get_noresume(kdev); |
4281 | 4334 | ||
4282 | track_intel_runtime_pm_wakeref(i915); | 4335 | return track_intel_runtime_pm_wakeref(i915); |
4283 | } | 4336 | } |
4284 | 4337 | ||
4285 | /** | 4338 | /** |
@@ -4290,7 +4343,7 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *i915) | |||
4290 | * intel_runtime_pm_get() and might power down the corresponding | 4343 | * intel_runtime_pm_get() and might power down the corresponding |
4291 | * hardware block right away if this is the last reference. | 4344 | * hardware block right away if this is the last reference. |
4292 | */ | 4345 | */ |
4293 | void intel_runtime_pm_put(struct drm_i915_private *i915) | 4346 | void intel_runtime_pm_put_unchecked(struct drm_i915_private *i915) |
4294 | { | 4347 | { |
4295 | struct pci_dev *pdev = i915->drm.pdev; | 4348 | struct pci_dev *pdev = i915->drm.pdev; |
4296 | struct device *kdev = &pdev->dev; | 4349 | struct device *kdev = &pdev->dev; |
@@ -4301,6 +4354,14 @@ void intel_runtime_pm_put(struct drm_i915_private *i915) | |||
4301 | pm_runtime_put_autosuspend(kdev); | 4354 | pm_runtime_put_autosuspend(kdev); |
4302 | } | 4355 | } |
4303 | 4356 | ||
4357 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) | ||
4358 | void intel_runtime_pm_put(struct drm_i915_private *i915, intel_wakeref_t wref) | ||
4359 | { | ||
4360 | cancel_intel_runtime_pm_wakeref(i915, wref); | ||
4361 | intel_runtime_pm_put_unchecked(i915); | ||
4362 | } | ||
4363 | #endif | ||
4364 | |||
4304 | /** | 4365 | /** |
4305 | * intel_runtime_pm_enable - enable runtime pm | 4366 | * intel_runtime_pm_enable - enable runtime pm |
4306 | * @i915: i915 device instance | 4367 | * @i915: i915 device instance |