Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: convert crtc and connection_mutex to ww_mutex (v5)

For atomic, it will be quite necessary to not need to care so much
about locking order. And 'state' gives us a convenient place to stash a
ww_ctx for any sort of update that needs to grab multiple crtc locks.

Because we will want to eventually make locking even more fine grained
(giving locks to planes, connectors, etc), split out drm_modeset_lock
and drm_modeset_acquire_ctx to track acquired locks.

Atomic will use this to keep track of which locks have been acquired
in a transaction.

v1: original
v2: remove a few things not needed until atomic, for now
v3: update for v3 of connection_mutex patch..
v4: squash in docbook
v5: doc tweaks/fixes

Signed-off-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Rob Clark and committed by
Dave Airlie
51fd371b 4f71d0cb

+531 -87
+6
Documentation/DocBook/drm.tmpl
··· 1791 1791 <title>KMS API Functions</title> 1792 1792 !Edrivers/gpu/drm/drm_crtc.c 1793 1793 </sect2> 1794 + <sect2> 1795 + <title>KMS Locking</title> 1796 + !Pdrivers/gpu/drm/drm_modeset_lock.c kms locking 1797 + !Iinclude/drm/drm_modeset_lock.h 1798 + !Edrivers/gpu/drm/drm_modeset_lock.c 1799 + </sect2> 1794 1800 </sect1> 1795 1801 1796 1802 <!-- Internals: kms helper functions -->
+2 -1
drivers/gpu/drm/Makefile
··· 13 13 drm_crtc.o drm_modes.o drm_edid.o \ 14 14 drm_info.o drm_debugfs.o drm_encoder_slave.o \ 15 15 drm_trace_points.o drm_global.o drm_prime.o \ 16 - drm_rect.o drm_vma_manager.o drm_flip_work.o 16 + drm_rect.o drm_vma_manager.o drm_flip_work.o \ 17 + drm_modeset_lock.o 17 18 18 19 drm-$(CONFIG_COMPAT) += drm_ioc32.o 19 20 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
+63 -22
drivers/gpu/drm/drm_crtc.c
··· 37 37 #include <drm/drm_crtc.h> 38 38 #include <drm/drm_edid.h> 39 39 #include <drm/drm_fourcc.h> 40 + #include <drm/drm_modeset_lock.h> 40 41 41 42 #include "drm_crtc_internal.h" 42 43 ··· 51 50 */ 52 51 void drm_modeset_lock_all(struct drm_device *dev) 53 52 { 54 - struct drm_crtc *crtc; 53 + struct drm_mode_config *config = &dev->mode_config; 54 + struct drm_modeset_acquire_ctx *ctx; 55 + int ret; 55 56 56 - mutex_lock(&dev->mode_config.mutex); 57 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 58 + if (WARN_ON(!ctx)) 59 + return; 57 60 58 - mutex_lock(&dev->mode_config.connection_mutex); 61 + mutex_lock(&config->mutex); 59 62 60 - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 61 - mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); 63 + drm_modeset_acquire_init(ctx, 0); 64 + 65 + retry: 66 + ret = drm_modeset_lock(&config->connection_mutex, ctx); 67 + if (ret) 68 + goto fail; 69 + ret = drm_modeset_lock_all_crtcs(dev, ctx); 70 + if (ret) 71 + goto fail; 72 + 73 + WARN_ON(config->acquire_ctx); 74 + 75 + /* now we hold the locks, so now that it is safe, stash the 76 + * ctx for drm_modeset_unlock_all(): 77 + */ 78 + config->acquire_ctx = ctx; 79 + 80 + drm_warn_on_modeset_not_all_locked(dev); 81 + 82 + return; 83 + 84 + fail: 85 + if (ret == -EDEADLK) { 86 + drm_modeset_backoff(ctx); 87 + goto retry; 88 + } 62 89 } 63 90 EXPORT_SYMBOL(drm_modeset_lock_all); 64 91 ··· 98 69 */ 99 70 void drm_modeset_unlock_all(struct drm_device *dev) 100 71 { 101 - struct drm_crtc *crtc; 72 + struct drm_mode_config *config = &dev->mode_config; 73 + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; 102 74 103 - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 104 - mutex_unlock(&crtc->mutex); 75 + if (WARN_ON(!ctx)) 76 + return; 105 77 106 - mutex_unlock(&dev->mode_config.connection_mutex); 78 + config->acquire_ctx = NULL; 79 + drm_modeset_drop_locks(ctx); 80 + drm_modeset_acquire_fini(ctx); 81 + 82 + kfree(ctx); 107 83 108 84 mutex_unlock(&dev->mode_config.mutex); 109 85 } ··· 129 95 return; 130 96 131 97 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 132 - WARN_ON(!mutex_is_locked(&crtc->mutex)); 98 + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 133 99 134 - WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 100 + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 135 101 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 136 102 } 137 103 EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); ··· 705 671 } 706 672 EXPORT_SYMBOL(drm_framebuffer_remove); 707 673 674 + DEFINE_WW_CLASS(crtc_ww_class); 675 + 708 676 /** 709 677 * drm_crtc_init_with_planes - Initialise a new CRTC object with 710 678 * specified primary and cursor planes. ··· 726 690 void *cursor, 727 691 const struct drm_crtc_funcs *funcs) 728 692 { 693 + struct drm_mode_config *config = &dev->mode_config; 729 694 int ret; 730 695 731 696 crtc->dev = dev; ··· 734 697 crtc->invert_dimensions = false; 735 698 736 699 drm_modeset_lock_all(dev); 737 - mutex_init(&crtc->mutex); 738 - mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); 700 + drm_modeset_lock_init(&crtc->mutex); 701 + /* dropped by _unlock_all(): */ 702 + drm_modeset_lock(&crtc->mutex, config->acquire_ctx); 739 703 740 704 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 741 705 if (ret) ··· 744 706 745 707 crtc->base.properties = &crtc->properties; 746 708 747 - list_add_tail(&crtc->head, &dev->mode_config.crtc_list); 748 - dev->mode_config.num_crtc++; 709 + list_add_tail(&crtc->head, &config->crtc_list); 710 + config->num_crtc++; 749 711 750 712 crtc->primary = primary; 751 713 if (primary) ··· 772 734 773 735 kfree(crtc->gamma_store); 774 736 crtc->gamma_store = NULL; 737 + 738 + drm_modeset_lock_fini(&crtc->mutex); 775 739 776 740 drm_mode_object_put(dev, &crtc->base); 777 741 list_del(&crtc->head); ··· 1838 1798 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 1839 1799 1840 1800 mutex_lock(&dev->mode_config.mutex); 1841 - mutex_lock(&dev->mode_config.connection_mutex); 1801 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 1842 1802 1843 1803 connector = drm_connector_find(dev, out_resp->connector_id); 1844 1804 if (!connector) { ··· 1937 1897 out_resp->count_encoders = encoders_count; 1938 1898 1939 1899 out: 1940 - mutex_unlock(&dev->mode_config.connection_mutex); 1900 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 1941 1901 mutex_unlock(&dev->mode_config.mutex); 1942 1902 1943 1903 return ret; ··· 2521 2481 return -ENOENT; 2522 2482 } 2523 2483 2524 - mutex_lock(&crtc->mutex); 2484 + drm_modeset_lock(&crtc->mutex, NULL); 2525 2485 if (req->flags & DRM_MODE_CURSOR_BO) { 2526 2486 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2527 2487 ret = -ENXIO; ··· 2545 2505 } 2546 2506 } 2547 2507 out: 2548 - mutex_unlock(&crtc->mutex); 2508 + drm_modeset_unlock(&crtc->mutex); 2549 2509 2550 2510 return ret; 2551 2511 ··· 4238 4198 if (!crtc) 4239 4199 return -ENOENT; 4240 4200 4241 - mutex_lock(&crtc->mutex); 4201 + drm_modeset_lock(&crtc->mutex, NULL); 4242 4202 if (crtc->primary->fb == NULL) { 4243 4203 /* The framebuffer is currently unbound, presumably 4244 4204 * due to a hotplug event, that userspace has not ··· 4322 4282 drm_framebuffer_unreference(fb); 4323 4283 if (old_fb) 4324 4284 drm_framebuffer_unreference(old_fb); 4325 - mutex_unlock(&crtc->mutex); 4285 + drm_modeset_unlock(&crtc->mutex); 4326 4286 4327 4287 return ret; 4328 4288 } ··· 4687 4647 void drm_mode_config_init(struct drm_device *dev) 4688 4648 { 4689 4649 mutex_init(&dev->mode_config.mutex); 4690 - mutex_init(&dev->mode_config.connection_mutex); 4650 + drm_modeset_lock_init(&dev->mode_config.connection_mutex); 4691 4651 mutex_init(&dev->mode_config.idr_mutex); 4692 4652 mutex_init(&dev->mode_config.fb_lock); 4693 4653 INIT_LIST_HEAD(&dev->mode_config.fb_list); ··· 4787 4747 } 4788 4748 4789 4749 idr_destroy(&dev->mode_config.crtc_idr); 4750 + drm_modeset_lock_fini(&dev->mode_config.connection_mutex); 4790 4751 } 4791 4752 EXPORT_SYMBOL(drm_mode_config_cleanup);
+1 -2
drivers/gpu/drm/drm_crtc_helper.c
··· 89 89 struct drm_device *dev = encoder->dev; 90 90 91 91 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 92 - WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 93 - 92 + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 94 93 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 95 94 if (connector->encoder == encoder) 96 95 return true;
+4
drivers/gpu/drm/drm_fb_helper.c
··· 331 331 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 332 332 continue; 333 333 334 + /* NOTE: we use lockless flag below to avoid grabbing other 335 + * modeset locks. So just trylock the underlying mutex 336 + * directly: 337 + */ 334 338 if (!mutex_trylock(&dev->mode_config.mutex)) { 335 339 error = true; 336 340 continue;
+247
drivers/gpu/drm/drm_modeset_lock.c
··· 1 + /* 2 + * Copyright (C) 2014 Red Hat 3 + * Author: Rob Clark <robdclark@gmail.com> 4 + * 5 + * Permission is hereby granted, free of charge, to any person obtaining a 6 + * copy of this software and associated documentation files (the "Software"), 7 + * to deal in the Software without restriction, including without limitation 8 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 + * and/or sell copies of the Software, and to permit persons to whom the 10 + * Software is furnished to do so, subject to the following conditions: 11 + * 12 + * The above copyright notice and this permission notice shall be included in 13 + * all copies or substantial portions of the Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 + * OTHER DEALINGS IN THE SOFTWARE. 22 + */ 23 + 24 + #include <drm/drmP.h> 25 + #include <drm/drm_crtc.h> 26 + #include <drm/drm_modeset_lock.h> 27 + 28 + /** 29 + * DOC: kms locking 30 + * 31 + * As KMS moves toward more fine grained locking, and atomic ioctl where 32 + * userspace can indirectly control locking order, it becomes necessary 33 + * to use ww_mutex and acquire-contexts to avoid deadlocks. But because 34 + * the locking is more distributed around the driver code, we want a bit 35 + * of extra utility/tracking out of our acquire-ctx. This is provided 36 + * by drm_modeset_lock / drm_modeset_acquire_ctx. 37 + * 38 + * For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt 39 + * 40 + * The basic usage pattern is to: 41 + * 42 + * drm_modeset_acquire_init(&ctx) 43 + * retry: 44 + * foreach (lock in random_ordered_set_of_locks) { 45 + * ret = drm_modeset_lock(lock, &ctx) 46 + * if (ret == -EDEADLK) { 47 + * drm_modeset_backoff(&ctx); 48 + * goto retry; 49 + * } 50 + * } 51 + * 52 + * ... do stuff ... 53 + * 54 + * drm_modeset_drop_locks(&ctx); 55 + * drm_modeset_acquire_fini(&ctx); 56 + */ 57 + 58 + 59 + /** 60 + * drm_modeset_acquire_init - initialize acquire context 61 + * @ctx: the acquire context 62 + * @flags: for future 63 + */ 64 + void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 65 + uint32_t flags) 66 + { 67 + ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class); 68 + INIT_LIST_HEAD(&ctx->locked); 69 + } 70 + EXPORT_SYMBOL(drm_modeset_acquire_init); 71 + 72 + /** 73 + * drm_modeset_acquire_fini - cleanup acquire context 74 + * @ctx: the acquire context 75 + */ 76 + void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx) 77 + { 78 + ww_acquire_fini(&ctx->ww_ctx); 79 + } 80 + EXPORT_SYMBOL(drm_modeset_acquire_fini); 81 + 82 + /** 83 + * drm_modeset_drop_locks - drop all locks 84 + * @ctx: the acquire context 85 + * 86 + * Drop all locks currently held against this acquire context. 87 + */ 88 + void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx) 89 + { 90 + WARN_ON(ctx->contended); 91 + while (!list_empty(&ctx->locked)) { 92 + struct drm_modeset_lock *lock; 93 + 94 + lock = list_first_entry(&ctx->locked, 95 + struct drm_modeset_lock, head); 96 + 97 + drm_modeset_unlock(lock); 98 + } 99 + } 100 + EXPORT_SYMBOL(drm_modeset_drop_locks); 101 + 102 + static inline int modeset_lock(struct drm_modeset_lock *lock, 103 + struct drm_modeset_acquire_ctx *ctx, 104 + bool interruptible, bool slow) 105 + { 106 + int ret; 107 + 108 + WARN_ON(ctx->contended); 109 + 110 + if (interruptible && slow) { 111 + ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); 112 + } else if (interruptible) { 113 + ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); 114 + } else if (slow) { 115 + ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx); 116 + ret = 0; 117 + } else { 118 + ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx); 119 + } 120 + if (!ret) { 121 + WARN_ON(!list_empty(&lock->head)); 122 + list_add(&lock->head, &ctx->locked); 123 + } else if (ret == -EALREADY) { 124 + /* we already hold the lock.. this is fine. For atomic 125 + * we will need to be able to drm_modeset_lock() things 126 + * without having to keep track of what is already locked 127 + * or not. 128 + */ 129 + ret = 0; 130 + } else if (ret == -EDEADLK) { 131 + ctx->contended = lock; 132 + } 133 + 134 + return ret; 135 + } 136 + 137 + static int modeset_backoff(struct drm_modeset_acquire_ctx *ctx, 138 + bool interruptible) 139 + { 140 + struct drm_modeset_lock *contended = ctx->contended; 141 + 142 + ctx->contended = NULL; 143 + 144 + if (WARN_ON(!contended)) 145 + return 0; 146 + 147 + drm_modeset_drop_locks(ctx); 148 + 149 + return modeset_lock(contended, ctx, interruptible, true); 150 + } 151 + 152 + /** 153 + * drm_modeset_backoff - deadlock avoidance backoff 154 + * @ctx: the acquire context 155 + * 156 + * If deadlock is detected (ie. drm_modeset_lock() returns -EDEADLK), 157 + * you must call this function to drop all currently held locks and 158 + * block until the contended lock becomes available. 159 + */ 160 + void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx) 161 + { 162 + modeset_backoff(ctx, false); 163 + } 164 + EXPORT_SYMBOL(drm_modeset_backoff); 165 + 166 + /** 167 + * drm_modeset_backoff_interruptible - deadlock avoidance backoff 168 + * @ctx: the acquire context 169 + * 170 + * Interruptible version of drm_modeset_backoff() 171 + */ 172 + int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx) 173 + { 174 + return modeset_backoff(ctx, true); 175 + } 176 + EXPORT_SYMBOL(drm_modeset_backoff_interruptible); 177 + 178 + /** 179 + * drm_modeset_lock - take modeset lock 180 + * @lock: lock to take 181 + * @ctx: acquire ctx 182 + * 183 + * If ctx is not NULL, then its ww acquire context is used and the 184 + * lock will be tracked by the context and can be released by calling 185 + * drm_modeset_drop_locks(). If -EDEADLK is returned, this means a 186 + * deadlock scenario has been detected and it is an error to attempt 187 + * to take any more locks without first calling drm_modeset_backoff(). 188 + */ 189 + int drm_modeset_lock(struct drm_modeset_lock *lock, 190 + struct drm_modeset_acquire_ctx *ctx) 191 + { 192 + if (ctx) 193 + return modeset_lock(lock, ctx, false, false); 194 + 195 + ww_mutex_lock(&lock->mutex, NULL); 196 + return 0; 197 + } 198 + EXPORT_SYMBOL(drm_modeset_lock); 199 + 200 + /** 201 + * drm_modeset_lock_interruptible - take modeset lock 202 + * @lock: lock to take 203 + * @ctx: acquire ctx 204 + * 205 + * Interruptible version of drm_modeset_lock() 206 + */ 207 + int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, 208 + struct drm_modeset_acquire_ctx *ctx) 209 + { 210 + if (ctx) 211 + return modeset_lock(lock, ctx, true, false); 212 + 213 + return ww_mutex_lock_interruptible(&lock->mutex, NULL); 214 + } 215 + EXPORT_SYMBOL(drm_modeset_lock_interruptible); 216 + 217 + /** 218 + * drm_modeset_unlock - drop modeset lock 219 + * @lock: lock to release 220 + */ 221 + void drm_modeset_unlock(struct drm_modeset_lock *lock) 222 + { 223 + list_del_init(&lock->head); 224 + ww_mutex_unlock(&lock->mutex); 225 + } 226 + EXPORT_SYMBOL(drm_modeset_unlock); 227 + 228 + /* Temporary.. until we have sufficiently fine grained locking, there 229 + * are a couple scenarios where it is convenient to grab all crtc locks. 230 + * It is planned to remove this: 231 + */ 232 + int drm_modeset_lock_all_crtcs(struct drm_device *dev, 233 + struct drm_modeset_acquire_ctx *ctx) 234 + { 235 + struct drm_mode_config *config = &dev->mode_config; 236 + struct drm_crtc *crtc; 237 + int ret = 0; 238 + 239 + list_for_each_entry(crtc, &config->crtc_list, head) { 240 + ret = drm_modeset_lock(&crtc->mutex, ctx); 241 + if (ret) 242 + return ret; 243 + } 244 + 245 + return 0; 246 + } 247 + EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
+1 -1
drivers/gpu/drm/drm_plane_helper.c
··· 60 60 * need to grab the connection_mutex here to be able to make these 61 61 * checks. 62 62 */ 63 - WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 63 + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 64 64 65 65 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 66 66 if (connector->encoder && connector->encoder->crtc == crtc) {
+3 -2
drivers/gpu/drm/i915/intel_crt.c
··· 630 630 enum intel_display_power_domain power_domain; 631 631 enum drm_connector_status status; 632 632 struct intel_load_detect_pipe tmp; 633 + struct drm_modeset_acquire_ctx ctx; 633 634 634 635 intel_runtime_pm_get(dev_priv); 635 636 ··· 674 673 } 675 674 676 675 /* for pre-945g platforms use load detect */ 677 - if (intel_get_load_detect_pipe(connector, NULL, &tmp)) { 676 + if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { 678 677 if (intel_crt_detect_ddc(connector)) 679 678 status = connector_status_connected; 680 679 else 681 680 status = intel_crt_load_detect(crt); 682 - intel_release_load_detect_pipe(connector, &tmp); 681 + intel_release_load_detect_pipe(connector, &tmp, &ctx); 683 682 } else 684 683 status = connector_status_unknown; 685 684
+37 -19
drivers/gpu/drm/i915/intel_display.c
··· 2576 2576 for_each_crtc(dev, crtc) { 2577 2577 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 2578 2578 2579 - mutex_lock(&crtc->mutex); 2579 + drm_modeset_lock(&crtc->mutex, NULL); 2580 2580 /* 2581 2581 * FIXME: Once we have proper support for primary planes (and 2582 2582 * disabling them without disabling the entire crtc) allow again ··· 2587 2587 crtc->primary->fb, 2588 2588 crtc->x, 2589 2589 crtc->y); 2590 - mutex_unlock(&crtc->mutex); 2590 + drm_modeset_unlock(&crtc->mutex); 2591 2591 } 2592 2592 } 2593 2593 ··· 8307 8307 8308 8308 bool intel_get_load_detect_pipe(struct drm_connector *connector, 8309 8309 struct drm_display_mode *mode, 8310 - struct intel_load_detect_pipe *old) 8310 + struct intel_load_detect_pipe *old, 8311 + struct drm_modeset_acquire_ctx *ctx) 8311 8312 { 8312 8313 struct intel_crtc *intel_crtc; 8313 8314 struct intel_encoder *intel_encoder = ··· 8318 8317 struct drm_crtc *crtc = NULL; 8319 8318 struct drm_device *dev = encoder->dev; 8320 8319 struct drm_framebuffer *fb; 8321 - int i = -1; 8320 + struct drm_mode_config *config = &dev->mode_config; 8321 + int ret, i = -1; 8322 8322 8323 8323 DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", 8324 8324 connector->base.id, connector->name, 8325 8325 encoder->base.id, encoder->name); 8326 8326 8327 - mutex_lock(&dev->mode_config.connection_mutex); 8327 + drm_modeset_acquire_init(ctx, 0); 8328 + 8329 + retry: 8330 + ret = drm_modeset_lock(&config->connection_mutex, ctx); 8331 + if (ret) 8332 + goto fail_unlock; 8328 8333 8329 8334 /* 8330 8335 * Algorithm gets a little messy: ··· 8346 8339 if (encoder->crtc) { 8347 8340 crtc = encoder->crtc; 8348 8341 8349 - mutex_lock(&crtc->mutex); 8342 + ret = drm_modeset_lock(&crtc->mutex, ctx); 8343 + if (ret) 8344 + goto fail_unlock; 8350 8345 8351 8346 old->dpms_mode = connector->dpms; 8352 8347 old->load_detect_temp = false; ··· 8376 8367 */ 8377 8368 if (!crtc) { 8378 8369 DRM_DEBUG_KMS("no pipe available for load-detect\n"); 8379 - goto fail_unlock_connector; 8370 + goto fail_unlock; 8380 8371 } 8381 8372 8382 - mutex_lock(&crtc->mutex); 8373 + ret = drm_modeset_lock(&crtc->mutex, ctx); 8374 + if (ret) 8375 + goto fail_unlock; 8383 8376 intel_encoder->new_crtc = to_intel_crtc(crtc); 8384 8377 to_intel_connector(connector)->new_encoder = intel_encoder; 8385 8378 ··· 8431 8420 intel_crtc->new_config = &intel_crtc->config; 8432 8421 else 8433 8422 intel_crtc->new_config = NULL; 8434 - mutex_unlock(&crtc->mutex); 8435 - fail_unlock_connector: 8436 - mutex_unlock(&dev->mode_config.connection_mutex); 8423 + fail_unlock: 8424 + if (ret == -EDEADLK) { 8425 + drm_modeset_backoff(ctx); 8426 + goto retry; 8427 + } 8428 + 8429 + drm_modeset_drop_locks(ctx); 8430 + drm_modeset_acquire_fini(ctx); 8437 8431 8438 8432 return false; 8439 8433 } 8440 8434 8441 8435 void intel_release_load_detect_pipe(struct drm_connector *connector, 8442 - struct intel_load_detect_pipe *old) 8436 + struct intel_load_detect_pipe *old, 8437 + struct drm_modeset_acquire_ctx *ctx) 8443 8438 { 8444 8439 struct intel_encoder *intel_encoder = 8445 8440 intel_attached_encoder(connector); ··· 8469 8452 drm_framebuffer_unreference(old->release_fb); 8470 8453 } 8471 8454 8472 - mutex_unlock(&crtc->mutex); 8473 - mutex_unlock(&connector->dev->mode_config.connection_mutex); 8455 + goto unlock; 8474 8456 return; 8475 8457 } 8476 8458 ··· 8477 8461 if (old->dpms_mode != DRM_MODE_DPMS_ON) 8478 8462 connector->funcs->dpms(connector, old->dpms_mode); 8479 8463 8480 - mutex_unlock(&crtc->mutex); 8481 - mutex_unlock(&connector->dev->mode_config.connection_mutex); 8464 + unlock: 8465 + drm_modeset_drop_locks(ctx); 8466 + drm_modeset_acquire_fini(ctx); 8482 8467 } 8483 8468 8484 8469 static int i9xx_pll_refclk(struct drm_device *dev, ··· 11012 10995 struct drm_encoder *encoder = connector->base.encoder; 11013 10996 struct drm_device *dev = connector->base.dev; 11014 10997 11015 - WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 10998 + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 11016 10999 11017 11000 if (!encoder) 11018 11001 return INVALID_PIPE; ··· 11822 11805 struct intel_connector *connector; 11823 11806 struct drm_connector *crt = NULL; 11824 11807 struct intel_load_detect_pipe load_detect_temp; 11808 + struct drm_modeset_acquire_ctx ctx; 11825 11809 11826 11810 /* We can't just switch on the pipe A, we need to set things up with a 11827 11811 * proper mode and output configuration. As a gross hack, enable pipe A ··· 11839 11821 if (!crt) 11840 11822 return; 11841 11823 11842 - if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp)) 11843 - intel_release_load_detect_pipe(crt, &load_detect_temp); 11824 + if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, &ctx)) 11825 + intel_release_load_detect_pipe(crt, &load_detect_temp, &ctx); 11844 11826 11845 11827 11846 11828 }
+7 -7
drivers/gpu/drm/i915/intel_dp.c
··· 1154 1154 u32 pp; 1155 1155 u32 pp_stat_reg, pp_ctrl_reg; 1156 1156 1157 - WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 1157 + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 1158 1158 1159 1159 if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) { 1160 1160 struct intel_digital_port *intel_dig_port = ··· 1191 1191 struct intel_dp, panel_vdd_work); 1192 1192 struct drm_device *dev = intel_dp_to_dev(intel_dp); 1193 1193 1194 - mutex_lock(&dev->mode_config.connection_mutex); 1194 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 1195 1195 edp_panel_vdd_off_sync(intel_dp); 1196 - mutex_unlock(&dev->mode_config.connection_mutex); 1196 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 1197 1197 } 1198 1198 1199 1199 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) ··· 3666 3666 drm_encoder_cleanup(encoder); 3667 3667 if (is_edp(intel_dp)) { 3668 3668 cancel_delayed_work_sync(&intel_dp->panel_vdd_work); 3669 - mutex_lock(&dev->mode_config.connection_mutex); 3669 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 3670 3670 edp_panel_vdd_off_sync(intel_dp); 3671 - mutex_unlock(&dev->mode_config.connection_mutex); 3671 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 3672 3672 } 3673 3673 kfree(intel_dig_port); 3674 3674 } ··· 4247 4247 drm_dp_aux_unregister(&intel_dp->aux); 4248 4248 if (is_edp(intel_dp)) { 4249 4249 cancel_delayed_work_sync(&intel_dp->panel_vdd_work); 4250 - mutex_lock(&dev->mode_config.connection_mutex); 4250 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 4251 4251 edp_panel_vdd_off_sync(intel_dp); 4252 - mutex_unlock(&dev->mode_config.connection_mutex); 4252 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 4253 4253 } 4254 4254 drm_sysfs_connector_remove(connector); 4255 4255 drm_connector_cleanup(connector);
+4 -2
drivers/gpu/drm/i915/intel_drv.h
··· 748 748 struct intel_digital_port *dport); 749 749 bool intel_get_load_detect_pipe(struct drm_connector *connector, 750 750 struct drm_display_mode *mode, 751 - struct intel_load_detect_pipe *old); 751 + struct intel_load_detect_pipe *old, 752 + struct drm_modeset_acquire_ctx *ctx); 752 753 void intel_release_load_detect_pipe(struct drm_connector *connector, 753 - struct intel_load_detect_pipe *old); 754 + struct intel_load_detect_pipe *old, 755 + struct drm_modeset_acquire_ctx *ctx); 754 756 int intel_pin_and_fence_fb_obj(struct drm_device *dev, 755 757 struct drm_i915_gem_object *obj, 756 758 struct intel_engine_cs *pipelined);
+2 -2
drivers/gpu/drm/i915/intel_opregion.c
··· 410 410 if (bclp > 255) 411 411 return ASLC_BACKLIGHT_FAILED; 412 412 413 - mutex_lock(&dev->mode_config.connection_mutex); 413 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 414 414 415 415 /* 416 416 * Update backlight on all connectors that support backlight (usually ··· 421 421 intel_panel_set_backlight(intel_connector, bclp, 255); 422 422 iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); 423 423 424 - mutex_unlock(&dev->mode_config.connection_mutex); 424 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 425 425 426 426 427 427 return 0;
+2 -2
drivers/gpu/drm/i915/intel_overlay.c
··· 688 688 u32 swidth, swidthsw, sheight, ostride; 689 689 690 690 BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 691 - BUG_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 691 + BUG_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 692 692 BUG_ON(!overlay); 693 693 694 694 ret = intel_overlay_release_old_vid(overlay); ··· 793 793 int ret; 794 794 795 795 BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 796 - BUG_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 796 + BUG_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 797 797 798 798 ret = intel_overlay_recover_from_interrupt(overlay); 799 799 if (ret != 0)
+4 -4
drivers/gpu/drm/i915/intel_panel.c
··· 876 876 struct intel_connector *connector = bl_get_data(bd); 877 877 struct drm_device *dev = connector->base.dev; 878 878 879 - mutex_lock(&dev->mode_config.connection_mutex); 879 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 880 880 DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", 881 881 bd->props.brightness, bd->props.max_brightness); 882 882 intel_panel_set_backlight(connector, bd->props.brightness, 883 883 bd->props.max_brightness); 884 - mutex_unlock(&dev->mode_config.connection_mutex); 884 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 885 885 return 0; 886 886 } 887 887 ··· 893 893 int ret; 894 894 895 895 intel_runtime_pm_get(dev_priv); 896 - mutex_lock(&dev->mode_config.connection_mutex); 896 + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); 897 897 ret = intel_panel_get_backlight(connector); 898 - mutex_unlock(&dev->mode_config.connection_mutex); 898 + drm_modeset_unlock(&dev->mode_config.connection_mutex); 899 899 intel_runtime_pm_put(dev_priv); 900 900 901 901 return ret;
+1 -1
drivers/gpu/drm/i915/intel_sprite.c
··· 55 55 int scanline, min, max, vblank_start; 56 56 DEFINE_WAIT(wait); 57 57 58 - WARN_ON(!mutex_is_locked(&crtc->base.mutex)); 58 + WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex)); 59 59 60 60 vblank_start = mode->crtc_vblank_start; 61 61 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+3 -2
drivers/gpu/drm/i915/intel_tv.c
··· 1321 1321 1322 1322 if (force) { 1323 1323 struct intel_load_detect_pipe tmp; 1324 + struct drm_modeset_acquire_ctx ctx; 1324 1325 1325 - if (intel_get_load_detect_pipe(connector, &mode, &tmp)) { 1326 + if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { 1326 1327 type = intel_tv_detect_type(intel_tv, connector); 1327 - intel_release_load_detect_pipe(connector, &tmp); 1328 + intel_release_load_detect_pipe(connector, &tmp, &ctx); 1328 1329 } else 1329 1330 return connector_status_unknown; 1330 1331 } else
+5 -5
drivers/gpu/drm/omapdrm/omap_crtc.c
··· 319 319 struct drm_display_mode *mode = &crtc->mode; 320 320 struct drm_gem_object *bo; 321 321 322 - mutex_lock(&crtc->mutex); 322 + drm_modeset_lock(&crtc->mutex, NULL); 323 323 omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, 324 324 0, 0, mode->hdisplay, mode->vdisplay, 325 325 crtc->x << 16, crtc->y << 16, 326 326 mode->hdisplay << 16, mode->vdisplay << 16, 327 327 vblank_cb, crtc); 328 - mutex_unlock(&crtc->mutex); 328 + drm_modeset_unlock(&crtc->mutex); 329 329 330 330 bo = omap_framebuffer_bo(crtc->primary->fb, 0); 331 331 drm_gem_object_unreference_unlocked(bo); ··· 465 465 * the callbacks and list modification all serialized 466 466 * with respect to modesetting ioctls from userspace. 467 467 */ 468 - mutex_lock(&crtc->mutex); 468 + drm_modeset_lock(&crtc->mutex, NULL); 469 469 dispc_runtime_get(); 470 470 471 471 /* ··· 510 510 511 511 out: 512 512 dispc_runtime_put(); 513 - mutex_unlock(&crtc->mutex); 513 + drm_modeset_unlock(&crtc->mutex); 514 514 } 515 515 516 516 int omap_crtc_apply(struct drm_crtc *crtc, ··· 518 518 { 519 519 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 520 520 521 - WARN_ON(!mutex_is_locked(&crtc->mutex)); 521 + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 522 522 523 523 /* no need to queue it again if it is already queued: */ 524 524 if (apply->queued)
+4 -4
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
··· 187 187 * can do this since the caller in the drm core doesn't check anything 188 188 * which is protected by any looks. 189 189 */ 190 - mutex_unlock(&crtc->mutex); 190 + drm_modeset_unlock(&crtc->mutex); 191 191 drm_modeset_lock_all(dev_priv->dev); 192 192 193 193 /* A lot of the code assumes this */ ··· 252 252 ret = 0; 253 253 out: 254 254 drm_modeset_unlock_all(dev_priv->dev); 255 - mutex_lock(&crtc->mutex); 255 + drm_modeset_lock(&crtc->mutex, NULL); 256 256 257 257 return ret; 258 258 } ··· 273 273 * can do this since the caller in the drm core doesn't check anything 274 274 * which is protected by any looks. 275 275 */ 276 - mutex_unlock(&crtc->mutex); 276 + drm_modeset_unlock(&crtc->mutex); 277 277 drm_modeset_lock_all(dev_priv->dev); 278 278 279 279 vmw_cursor_update_position(dev_priv, shown, ··· 281 281 du->cursor_y + du->hotspot_y); 282 282 283 283 drm_modeset_unlock_all(dev_priv->dev); 284 - mutex_lock(&crtc->mutex); 284 + drm_modeset_lock(&crtc->mutex, NULL); 285 285 286 286 return 0; 287 287 }
-5
include/drm/drmP.h
··· 1186 1186 return ret; 1187 1187 } 1188 1188 1189 - static inline bool drm_modeset_is_locked(struct drm_device *dev) 1190 - { 1191 - return mutex_is_locked(&dev->mode_config.mutex); 1192 - } 1193 - 1194 1189 static inline bool drm_is_render_client(const struct drm_file *file_priv) 1195 1190 { 1196 1191 return file_priv->minor->type == DRM_MINOR_RENDER;
+9 -6
include/drm/drm_crtc.h
··· 33 33 #include <linux/hdmi.h> 34 34 #include <drm/drm_mode.h> 35 35 #include <drm/drm_fourcc.h> 36 + #include <drm/drm_modeset_lock.h> 36 37 37 38 struct drm_device; 38 39 struct drm_mode_set; ··· 206 205 struct list_head enum_blob_list; 207 206 }; 208 207 208 + void drm_modeset_lock_all(struct drm_device *dev); 209 + void drm_modeset_unlock_all(struct drm_device *dev); 210 + void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); 211 + 209 212 struct drm_crtc; 210 213 struct drm_connector; 211 214 struct drm_encoder; ··· 285 280 * drm_crtc - central CRTC control structure 286 281 * @dev: parent DRM device 287 282 * @head: list management 283 + * @mutex: per-CRTC locking 288 284 * @base: base KMS object for ID tracking etc. 289 285 * @primary: primary plane for this CRTC 290 286 * @cursor: cursor plane for this CRTC ··· 320 314 * state, ...) and a write lock for everything which can be update 321 315 * without a full modeset (fb, cursor data, ...) 322 316 */ 323 - struct mutex mutex; 317 + struct drm_modeset_lock mutex; 324 318 325 319 struct drm_mode_object base; 326 320 ··· 744 738 */ 745 739 struct drm_mode_config { 746 740 struct mutex mutex; /* protects configuration (mode lists etc.) */ 747 - struct mutex connection_mutex; /* protects connector->encoder and encoder->crtc links */ 741 + struct drm_modeset_lock connection_mutex; /* protects connector->encoder and encoder->crtc links */ 742 + struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ 748 743 struct mutex idr_mutex; /* for IDR management */ 749 744 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ 750 745 /* this is limited to one for now */ ··· 845 838 int type; 846 839 char *name; 847 840 }; 848 - 849 - extern void drm_modeset_lock_all(struct drm_device *dev); 850 - extern void drm_modeset_unlock_all(struct drm_device *dev); 851 - extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); 852 841 853 842 extern int drm_crtc_init_with_planes(struct drm_device *dev, 854 843 struct drm_crtc *crtc,
+126
include/drm/drm_modeset_lock.h
··· 1 + /* 2 + * Copyright (C) 2014 Red Hat 3 + * Author: Rob Clark <robdclark@gmail.com> 4 + * 5 + * Permission is hereby granted, free of charge, to any person obtaining a 6 + * copy of this software and associated documentation files (the "Software"), 7 + * to deal in the Software without restriction, including without limitation 8 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 + * and/or sell copies of the Software, and to permit persons to whom the 10 + * Software is furnished to do so, subject to the following conditions: 11 + * 12 + * The above copyright notice and this permission notice shall be included in 13 + * all copies or substantial portions of the Software. 14 + * 15 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 + * OTHER DEALINGS IN THE SOFTWARE. 22 + */ 23 + 24 + #ifndef DRM_MODESET_LOCK_H_ 25 + #define DRM_MODESET_LOCK_H_ 26 + 27 + #include <linux/ww_mutex.h> 28 + 29 + struct drm_modeset_lock; 30 + 31 + /** 32 + * drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) 33 + * @ww_ctx: base acquire ctx 34 + * @contended: used internally for -EDEADLK handling 35 + * @locked: list of held locks 36 + * 37 + * Each thread competing for a set of locks must use one acquire 38 + * ctx. And if any lock fxn returns -EDEADLK, it must backoff and 39 + * retry. 40 + */ 41 + struct drm_modeset_acquire_ctx { 42 + 43 + struct ww_acquire_ctx ww_ctx; 44 + 45 + /** 46 + * Contended lock: if a lock is contended you should only call 47 + * drm_modeset_backoff() which drops locks and slow-locks the 48 + * contended lock. 49 + */ 50 + struct drm_modeset_lock *contended; 51 + 52 + /** 53 + * list of held locks (drm_modeset_lock) 54 + */ 55 + struct list_head locked; 56 + }; 57 + 58 + /** 59 + * drm_modeset_lock - used for locking modeset resources. 60 + * @mutex: resource locking 61 + * @head: used to hold it's place on state->locked list when 62 + * part of an atomic update 63 + * 64 + * Used for locking CRTCs and other modeset resources. 65 + */ 66 + struct drm_modeset_lock { 67 + /** 68 + * modeset lock 69 + */ 70 + struct ww_mutex mutex; 71 + 72 + /** 73 + * Resources that are locked as part of an atomic update are added 74 + * to a list (so we know what to unlock at the end). 75 + */ 76 + struct list_head head; 77 + }; 78 + 79 + extern struct ww_class crtc_ww_class; 80 + 81 + void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, 82 + uint32_t flags); 83 + void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); 84 + void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); 85 + void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); 86 + int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx); 87 + 88 + /** 89 + * drm_modeset_lock_init - initialize lock 90 + * @lock: lock to init 91 + */ 92 + static inline void drm_modeset_lock_init(struct drm_modeset_lock *lock) 93 + { 94 + ww_mutex_init(&lock->mutex, &crtc_ww_class); 95 + INIT_LIST_HEAD(&lock->head); 96 + } 97 + 98 + /** 99 + * drm_modeset_lock_fini - cleanup lock 100 + * @lock: lock to cleanup 101 + */ 102 + static inline void drm_modeset_lock_fini(struct drm_modeset_lock *lock) 103 + { 104 + WARN_ON(!list_empty(&lock->head)); 105 + } 106 + 107 + /** 108 + * drm_modeset_is_locked - equivalent to mutex_is_locked() 109 + * @lock: lock to check 110 + */ 111 + static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock) 112 + { 113 + return ww_mutex_is_locked(&lock->mutex); 114 + } 115 + 116 + int drm_modeset_lock(struct drm_modeset_lock *lock, 117 + struct drm_modeset_acquire_ctx *ctx); 118 + int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, 119 + struct drm_modeset_acquire_ctx *ctx); 120 + void drm_modeset_unlock(struct drm_modeset_lock *lock); 121 + 122 + struct drm_device; 123 + int drm_modeset_lock_all_crtcs(struct drm_device *dev, 124 + struct drm_modeset_acquire_ctx *ctx); 125 + 126 + #endif /* DRM_MODESET_LOCK_H_ */