aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_modeset_lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_modeset_lock.c')
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c213
1 files changed, 212 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 3a02e5e3e9f3..474e4d12a2d8 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -57,6 +57,212 @@
57 57
58 58
59/** 59/**
60 * __drm_modeset_lock_all - internal helper to grab all modeset locks
61 * @dev: DRM device
62 * @trylock: trylock mode for atomic contexts
63 *
64 * This is a special version of drm_modeset_lock_all() which can also be used in
65 * atomic contexts. Then @trylock must be set to true.
66 *
67 * Returns:
68 * 0 on success or negative error code on failure.
69 */
70int __drm_modeset_lock_all(struct drm_device *dev,
71 bool trylock)
72{
73 struct drm_mode_config *config = &dev->mode_config;
74 struct drm_modeset_acquire_ctx *ctx;
75 int ret;
76
77 ctx = kzalloc(sizeof(*ctx),
78 trylock ? GFP_ATOMIC : GFP_KERNEL);
79 if (!ctx)
80 return -ENOMEM;
81
82 if (trylock) {
83 if (!mutex_trylock(&config->mutex))
84 return -EBUSY;
85 } else {
86 mutex_lock(&config->mutex);
87 }
88
89 drm_modeset_acquire_init(ctx, 0);
90 ctx->trylock_only = trylock;
91
92retry:
93 ret = drm_modeset_lock(&config->connection_mutex, ctx);
94 if (ret)
95 goto fail;
96 ret = drm_modeset_lock_all_crtcs(dev, ctx);
97 if (ret)
98 goto fail;
99
100 WARN_ON(config->acquire_ctx);
101
102 /* now we hold the locks, so now that it is safe, stash the
103 * ctx for drm_modeset_unlock_all():
104 */
105 config->acquire_ctx = ctx;
106
107 drm_warn_on_modeset_not_all_locked(dev);
108
109 return 0;
110
111fail:
112 if (ret == -EDEADLK) {
113 drm_modeset_backoff(ctx);
114 goto retry;
115 }
116
117 return ret;
118}
119EXPORT_SYMBOL(__drm_modeset_lock_all);
120
121/**
122 * drm_modeset_lock_all - take all modeset locks
123 * @dev: drm device
124 *
125 * This function takes all modeset locks, suitable where a more fine-grained
126 * scheme isn't (yet) implemented. Locks must be dropped with
127 * drm_modeset_unlock_all.
128 */
129void drm_modeset_lock_all(struct drm_device *dev)
130{
131 WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
132}
133EXPORT_SYMBOL(drm_modeset_lock_all);
134
135/**
136 * drm_modeset_unlock_all - drop all modeset locks
137 * @dev: device
138 *
139 * This function drop all modeset locks taken by drm_modeset_lock_all.
140 */
141void drm_modeset_unlock_all(struct drm_device *dev)
142{
143 struct drm_mode_config *config = &dev->mode_config;
144 struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
145
146 if (WARN_ON(!ctx))
147 return;
148
149 config->acquire_ctx = NULL;
150 drm_modeset_drop_locks(ctx);
151 drm_modeset_acquire_fini(ctx);
152
153 kfree(ctx);
154
155 mutex_unlock(&dev->mode_config.mutex);
156}
157EXPORT_SYMBOL(drm_modeset_unlock_all);
158
159/**
160 * drm_modeset_lock_crtc - lock crtc with hidden acquire ctx
161 * @crtc: drm crtc
162 *
163 * This function locks the given crtc using a hidden acquire context. This is
164 * necessary so that drivers internally using the atomic interfaces can grab
165 * further locks with the lock acquire context.
166 */
167void drm_modeset_lock_crtc(struct drm_crtc *crtc)
168{
169 struct drm_modeset_acquire_ctx *ctx;
170 int ret;
171
172 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
173 if (WARN_ON(!ctx))
174 return;
175
176 drm_modeset_acquire_init(ctx, 0);
177
178retry:
179 ret = drm_modeset_lock(&crtc->mutex, ctx);
180 if (ret)
181 goto fail;
182
183 WARN_ON(crtc->acquire_ctx);
184
185 /* now we hold the locks, so now that it is safe, stash the
186 * ctx for drm_modeset_unlock_crtc():
187 */
188 crtc->acquire_ctx = ctx;
189
190 return;
191
192fail:
193 if (ret == -EDEADLK) {
194 drm_modeset_backoff(ctx);
195 goto retry;
196 }
197}
198EXPORT_SYMBOL(drm_modeset_lock_crtc);
199
200/**
201 * drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls
202 * @crtc: drm crtc
203 *
204 * Legacy ioctl operations like cursor updates or page flips only have per-crtc
205 * locking, and store the acquire ctx in the corresponding crtc. All other
206 * legacy operations take all locks and use a global acquire context. This
207 * function grabs the right one.
208 */
209struct drm_modeset_acquire_ctx *
210drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc)
211{
212 if (crtc->acquire_ctx)
213 return crtc->acquire_ctx;
214
215 WARN_ON(!crtc->dev->mode_config.acquire_ctx);
216
217 return crtc->dev->mode_config.acquire_ctx;
218}
219EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx);
220
221/**
222 * drm_modeset_unlock_crtc - drop crtc lock
223 * @crtc: drm crtc
224 *
225 * This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other
226 * locks acquired through the hidden context.
227 */
228void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
229{
230 struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx;
231
232 if (WARN_ON(!ctx))
233 return;
234
235 crtc->acquire_ctx = NULL;
236 drm_modeset_drop_locks(ctx);
237 drm_modeset_acquire_fini(ctx);
238
239 kfree(ctx);
240}
241EXPORT_SYMBOL(drm_modeset_unlock_crtc);
242
243/**
244 * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
245 * @dev: device
246 *
247 * Useful as a debug assert.
248 */
249void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
250{
251 struct drm_crtc *crtc;
252
253 /* Locking is currently fubar in the panic handler. */
254 if (oops_in_progress)
255 return;
256
257 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
258 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
259
260 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
261 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
262}
263EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
264
265/**
60 * drm_modeset_acquire_init - initialize acquire context 266 * drm_modeset_acquire_init - initialize acquire context
61 * @ctx: the acquire context 267 * @ctx: the acquire context
62 * @flags: for future 268 * @flags: for future
@@ -108,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
108 314
109 WARN_ON(ctx->contended); 315 WARN_ON(ctx->contended);
110 316
111 if (interruptible && slow) { 317 if (ctx->trylock_only) {
318 if (!ww_mutex_trylock(&lock->mutex))
319 return -EBUSY;
320 else
321 return 0;
322 } else if (interruptible && slow) {
112 ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); 323 ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
113 } else if (interruptible) { 324 } else if (interruptible) {
114 ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); 325 ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);