aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-11-19 12:10:12 -0500
committerDave Airlie <airlied@redhat.com>2014-06-04 19:54:33 -0400
commit51fd371bbaf94018a1223b4e2cf20b9880fd92d4 (patch)
treee86e8ec3ace2fd61111105d39f5eb2d37378e9a8
parent4f71d0cb76339a10fd445b0b281acc45c71b6271 (diff)
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>
-rw-r--r--Documentation/DocBook/drm.tmpl6
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/drm_crtc.c85
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c3
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c4
-rw-r--r--drivers/gpu/drm/drm_modeset_lock.c247
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c2
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c5
-rw-r--r--drivers/gpu/drm/i915/intel_display.c56
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c14
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h6
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c4
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c4
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c8
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c2
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c5
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c10
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c8
-rw-r--r--include/drm/drmP.h5
-rw-r--r--include/drm/drm_crtc.h15
-rw-r--r--include/drm/drm_modeset_lock.h126
21 files changed, 531 insertions, 87 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 00f1c25e53df..efef63717ef6 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -1791,6 +1791,12 @@ void intel_crt_init(struct drm_device *dev)
1791 <title>KMS API Functions</title> 1791 <title>KMS API Functions</title>
1792!Edrivers/gpu/drm/drm_crtc.c 1792!Edrivers/gpu/drm/drm_crtc.c
1793 </sect2> 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 </sect1> 1800 </sect1>
1795 1801
1796 <!-- Internals: kms helper functions --> 1802 <!-- Internals: kms helper functions -->
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 863db8415c22..dd2ba4269740 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
13 drm_crtc.o drm_modes.o drm_edid.o \ 13 drm_crtc.o drm_modes.o drm_edid.o \
14 drm_info.o drm_debugfs.o drm_encoder_slave.o \ 14 drm_info.o drm_debugfs.o drm_encoder_slave.o \
15 drm_trace_points.o drm_global.o drm_prime.o \ 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
18drm-$(CONFIG_COMPAT) += drm_ioc32.o 19drm-$(CONFIG_COMPAT) += drm_ioc32.o
19drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o 20drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f3b98d4b6f46..43735f38cd17 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -37,6 +37,7 @@
37#include <drm/drm_crtc.h> 37#include <drm/drm_crtc.h>
38#include <drm/drm_edid.h> 38#include <drm/drm_edid.h>
39#include <drm/drm_fourcc.h> 39#include <drm/drm_fourcc.h>
40#include <drm/drm_modeset_lock.h>
40 41
41#include "drm_crtc_internal.h" 42#include "drm_crtc_internal.h"
42 43
@@ -50,14 +51,42 @@
50 */ 51 */
51void drm_modeset_lock_all(struct drm_device *dev) 52void drm_modeset_lock_all(struct drm_device *dev)
52{ 53{
53 struct drm_crtc *crtc; 54 struct drm_mode_config *config = &dev->mode_config;
55 struct drm_modeset_acquire_ctx *ctx;
56 int ret;
54 57
55 mutex_lock(&dev->mode_config.mutex); 58 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
59 if (WARN_ON(!ctx))
60 return;
56 61
57 mutex_lock(&dev->mode_config.connection_mutex); 62 mutex_lock(&config->mutex);
58 63
59 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 64 drm_modeset_acquire_init(ctx, 0);
60 mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); 65
66retry:
67 ret = drm_modeset_lock(&config->connection_mutex, ctx);
68 if (ret)
69 goto fail;
70 ret = drm_modeset_lock_all_crtcs(dev, ctx);
71 if (ret)
72 goto fail;
73
74 WARN_ON(config->acquire_ctx);
75
76 /* now we hold the locks, so now that it is safe, stash the
77 * ctx for drm_modeset_unlock_all():
78 */
79 config->acquire_ctx = ctx;
80
81 drm_warn_on_modeset_not_all_locked(dev);
82
83 return;
84
85fail:
86 if (ret == -EDEADLK) {
87 drm_modeset_backoff(ctx);
88 goto retry;
89 }
61} 90}
62EXPORT_SYMBOL(drm_modeset_lock_all); 91EXPORT_SYMBOL(drm_modeset_lock_all);
63 92
@@ -69,12 +98,17 @@ EXPORT_SYMBOL(drm_modeset_lock_all);
69 */ 98 */
70void drm_modeset_unlock_all(struct drm_device *dev) 99void drm_modeset_unlock_all(struct drm_device *dev)
71{ 100{
72 struct drm_crtc *crtc; 101 struct drm_mode_config *config = &dev->mode_config;
102 struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
73 103
74 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 104 if (WARN_ON(!ctx))
75 mutex_unlock(&crtc->mutex); 105 return;
106
107 config->acquire_ctx = NULL;
108 drm_modeset_drop_locks(ctx);
109 drm_modeset_acquire_fini(ctx);
76 110
77 mutex_unlock(&dev->mode_config.connection_mutex); 111 kfree(ctx);
78 112
79 mutex_unlock(&dev->mode_config.mutex); 113 mutex_unlock(&dev->mode_config.mutex);
80} 114}
@@ -95,9 +129,9 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
95 return; 129 return;
96 130
97 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) 131 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
98 WARN_ON(!mutex_is_locked(&crtc->mutex)); 132 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
99 133
100 WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 134 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
101 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 135 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
102} 136}
103EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); 137EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
@@ -671,6 +705,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
671} 705}
672EXPORT_SYMBOL(drm_framebuffer_remove); 706EXPORT_SYMBOL(drm_framebuffer_remove);
673 707
708DEFINE_WW_CLASS(crtc_ww_class);
709
674/** 710/**
675 * drm_crtc_init_with_planes - Initialise a new CRTC object with 711 * drm_crtc_init_with_planes - Initialise a new CRTC object with
676 * specified primary and cursor planes. 712 * specified primary and cursor planes.
@@ -690,6 +726,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
690 void *cursor, 726 void *cursor,
691 const struct drm_crtc_funcs *funcs) 727 const struct drm_crtc_funcs *funcs)
692{ 728{
729 struct drm_mode_config *config = &dev->mode_config;
693 int ret; 730 int ret;
694 731
695 crtc->dev = dev; 732 crtc->dev = dev;
@@ -697,8 +734,9 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
697 crtc->invert_dimensions = false; 734 crtc->invert_dimensions = false;
698 735
699 drm_modeset_lock_all(dev); 736 drm_modeset_lock_all(dev);
700 mutex_init(&crtc->mutex); 737 drm_modeset_lock_init(&crtc->mutex);
701 mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); 738 /* dropped by _unlock_all(): */
739 drm_modeset_lock(&crtc->mutex, config->acquire_ctx);
702 740
703 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); 741 ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
704 if (ret) 742 if (ret)
@@ -706,8 +744,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
706 744
707 crtc->base.properties = &crtc->properties; 745 crtc->base.properties = &crtc->properties;
708 746
709 list_add_tail(&crtc->head, &dev->mode_config.crtc_list); 747 list_add_tail(&crtc->head, &config->crtc_list);
710 dev->mode_config.num_crtc++; 748 config->num_crtc++;
711 749
712 crtc->primary = primary; 750 crtc->primary = primary;
713 if (primary) 751 if (primary)
@@ -735,6 +773,8 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
735 kfree(crtc->gamma_store); 773 kfree(crtc->gamma_store);
736 crtc->gamma_store = NULL; 774 crtc->gamma_store = NULL;
737 775
776 drm_modeset_lock_fini(&crtc->mutex);
777
738 drm_mode_object_put(dev, &crtc->base); 778 drm_mode_object_put(dev, &crtc->base);
739 list_del(&crtc->head); 779 list_del(&crtc->head);
740 dev->mode_config.num_crtc--; 780 dev->mode_config.num_crtc--;
@@ -1798,7 +1838,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
1798 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); 1838 DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
1799 1839
1800 mutex_lock(&dev->mode_config.mutex); 1840 mutex_lock(&dev->mode_config.mutex);
1801 mutex_lock(&dev->mode_config.connection_mutex); 1841 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
1802 1842
1803 connector = drm_connector_find(dev, out_resp->connector_id); 1843 connector = drm_connector_find(dev, out_resp->connector_id);
1804 if (!connector) { 1844 if (!connector) {
@@ -1897,7 +1937,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
1897 out_resp->count_encoders = encoders_count; 1937 out_resp->count_encoders = encoders_count;
1898 1938
1899out: 1939out:
1900 mutex_unlock(&dev->mode_config.connection_mutex); 1940 drm_modeset_unlock(&dev->mode_config.connection_mutex);
1901 mutex_unlock(&dev->mode_config.mutex); 1941 mutex_unlock(&dev->mode_config.mutex);
1902 1942
1903 return ret; 1943 return ret;
@@ -2481,7 +2521,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
2481 return -ENOENT; 2521 return -ENOENT;
2482 } 2522 }
2483 2523
2484 mutex_lock(&crtc->mutex); 2524 drm_modeset_lock(&crtc->mutex, NULL);
2485 if (req->flags & DRM_MODE_CURSOR_BO) { 2525 if (req->flags & DRM_MODE_CURSOR_BO) {
2486 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2526 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
2487 ret = -ENXIO; 2527 ret = -ENXIO;
@@ -2505,7 +2545,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
2505 } 2545 }
2506 } 2546 }
2507out: 2547out:
2508 mutex_unlock(&crtc->mutex); 2548 drm_modeset_unlock(&crtc->mutex);
2509 2549
2510 return ret; 2550 return ret;
2511 2551
@@ -4198,7 +4238,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
4198 if (!crtc) 4238 if (!crtc)
4199 return -ENOENT; 4239 return -ENOENT;
4200 4240
4201 mutex_lock(&crtc->mutex); 4241 drm_modeset_lock(&crtc->mutex, NULL);
4202 if (crtc->primary->fb == NULL) { 4242 if (crtc->primary->fb == NULL) {
4203 /* The framebuffer is currently unbound, presumably 4243 /* The framebuffer is currently unbound, presumably
4204 * due to a hotplug event, that userspace has not 4244 * due to a hotplug event, that userspace has not
@@ -4282,7 +4322,7 @@ out:
4282 drm_framebuffer_unreference(fb); 4322 drm_framebuffer_unreference(fb);
4283 if (old_fb) 4323 if (old_fb)
4284 drm_framebuffer_unreference(old_fb); 4324 drm_framebuffer_unreference(old_fb);
4285 mutex_unlock(&crtc->mutex); 4325 drm_modeset_unlock(&crtc->mutex);
4286 4326
4287 return ret; 4327 return ret;
4288} 4328}
@@ -4647,7 +4687,7 @@ EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
4647void drm_mode_config_init(struct drm_device *dev) 4687void drm_mode_config_init(struct drm_device *dev)
4648{ 4688{
4649 mutex_init(&dev->mode_config.mutex); 4689 mutex_init(&dev->mode_config.mutex);
4650 mutex_init(&dev->mode_config.connection_mutex); 4690 drm_modeset_lock_init(&dev->mode_config.connection_mutex);
4651 mutex_init(&dev->mode_config.idr_mutex); 4691 mutex_init(&dev->mode_config.idr_mutex);
4652 mutex_init(&dev->mode_config.fb_lock); 4692 mutex_init(&dev->mode_config.fb_lock);
4653 INIT_LIST_HEAD(&dev->mode_config.fb_list); 4693 INIT_LIST_HEAD(&dev->mode_config.fb_list);
@@ -4747,5 +4787,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
4747 } 4787 }
4748 4788
4749 idr_destroy(&dev->mode_config.crtc_idr); 4789 idr_destroy(&dev->mode_config.crtc_idr);
4790 drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
4750} 4791}
4751EXPORT_SYMBOL(drm_mode_config_cleanup); 4792EXPORT_SYMBOL(drm_mode_config_cleanup);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index b55d27c872f6..eb1c062e04b2 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -89,8 +89,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
89 struct drm_device *dev = encoder->dev; 89 struct drm_device *dev = encoder->dev;
90 90
91 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 91 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
92 WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 92 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
93
94 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 93 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
95 if (connector->encoder == encoder) 94 if (connector->encoder == encoder)
96 return true; 95 return true;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 1ddc17464250..43329cee299f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -331,6 +331,10 @@ static bool drm_fb_helper_force_kernel_mode(void)
331 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 331 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
332 continue; 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 if (!mutex_trylock(&dev->mode_config.mutex)) { 338 if (!mutex_trylock(&dev->mode_config.mutex)) {
335 error = true; 339 error = true;
336 continue; 340 continue;
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
new file mode 100644
index 000000000000..7c2497dea1e9
--- /dev/null
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -0,0 +1,247 @@
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 */
64void 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}
70EXPORT_SYMBOL(drm_modeset_acquire_init);
71
72/**
73 * drm_modeset_acquire_fini - cleanup acquire context
74 * @ctx: the acquire context
75 */
76void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx)
77{
78 ww_acquire_fini(&ctx->ww_ctx);
79}
80EXPORT_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 */
88void 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}
100EXPORT_SYMBOL(drm_modeset_drop_locks);
101
102static 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
137static 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 */
160void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
161{
162 modeset_backoff(ctx, false);
163}
164EXPORT_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 */
172int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx)
173{
174 return modeset_backoff(ctx, true);
175}
176EXPORT_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 */
189int 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}
198EXPORT_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 */
207int 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}
215EXPORT_SYMBOL(drm_modeset_lock_interruptible);
216
217/**
218 * drm_modeset_unlock - drop modeset lock
219 * @lock: lock to release
220 */
221void drm_modeset_unlock(struct drm_modeset_lock *lock)
222{
223 list_del_init(&lock->head);
224 ww_mutex_unlock(&lock->mutex);
225}
226EXPORT_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 */
232int 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}
247EXPORT_SYMBOL(drm_modeset_lock_all_crtcs);
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index f3e0a23abf4e..1b15643b4586 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -60,7 +60,7 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc,
60 * need to grab the connection_mutex here to be able to make these 60 * need to grab the connection_mutex here to be able to make these
61 * checks. 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 list_for_each_entry(connector, &dev->mode_config.connector_list, head) 65 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
66 if (connector->encoder && connector->encoder->crtc == crtc) { 66 if (connector->encoder && connector->encoder->crtc == crtc) {
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 1fc91df58296..5a045d3bd77e 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -630,6 +630,7 @@ intel_crt_detect(struct drm_connector *connector, bool force)
630 enum intel_display_power_domain power_domain; 630 enum intel_display_power_domain power_domain;
631 enum drm_connector_status status; 631 enum drm_connector_status status;
632 struct intel_load_detect_pipe tmp; 632 struct intel_load_detect_pipe tmp;
633 struct drm_modeset_acquire_ctx ctx;
633 634
634 intel_runtime_pm_get(dev_priv); 635 intel_runtime_pm_get(dev_priv);
635 636
@@ -673,12 +674,12 @@ intel_crt_detect(struct drm_connector *connector, bool force)
673 } 674 }
674 675
675 /* for pre-945g platforms use load detect */ 676 /* for pre-945g platforms use load detect */
676 if (intel_get_load_detect_pipe(connector, NULL, &tmp)) { 677 if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) {
677 if (intel_crt_detect_ddc(connector)) 678 if (intel_crt_detect_ddc(connector))
678 status = connector_status_connected; 679 status = connector_status_connected;
679 else 680 else
680 status = intel_crt_load_detect(crt); 681 status = intel_crt_load_detect(crt);
681 intel_release_load_detect_pipe(connector, &tmp); 682 intel_release_load_detect_pipe(connector, &tmp, &ctx);
682 } else 683 } else
683 status = connector_status_unknown; 684 status = connector_status_unknown;
684 685
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c2976ade823f..1ce4ad4626e4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2576,7 +2576,7 @@ void intel_display_handle_reset(struct drm_device *dev)
2576 for_each_crtc(dev, crtc) { 2576 for_each_crtc(dev, crtc) {
2577 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 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 * FIXME: Once we have proper support for primary planes (and 2581 * FIXME: Once we have proper support for primary planes (and
2582 * disabling them without disabling the entire crtc) allow again 2582 * disabling them without disabling the entire crtc) allow again
@@ -2587,7 +2587,7 @@ void intel_display_handle_reset(struct drm_device *dev)
2587 crtc->primary->fb, 2587 crtc->primary->fb,
2588 crtc->x, 2588 crtc->x,
2589 crtc->y); 2589 crtc->y);
2590 mutex_unlock(&crtc->mutex); 2590 drm_modeset_unlock(&crtc->mutex);
2591 } 2591 }
2592} 2592}
2593 2593
@@ -8307,7 +8307,8 @@ mode_fits_in_fbdev(struct drm_device *dev,
8307 8307
8308bool intel_get_load_detect_pipe(struct drm_connector *connector, 8308bool intel_get_load_detect_pipe(struct drm_connector *connector,
8309 struct drm_display_mode *mode, 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 struct intel_crtc *intel_crtc; 8313 struct intel_crtc *intel_crtc;
8313 struct intel_encoder *intel_encoder = 8314 struct intel_encoder *intel_encoder =
@@ -8317,13 +8318,19 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
8317 struct drm_crtc *crtc = NULL; 8318 struct drm_crtc *crtc = NULL;
8318 struct drm_device *dev = encoder->dev; 8319 struct drm_device *dev = encoder->dev;
8319 struct drm_framebuffer *fb; 8320 struct drm_framebuffer *fb;
8320 int i = -1; 8321 struct drm_mode_config *config = &dev->mode_config;
8322 int ret, i = -1;
8321 8323
8322 DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", 8324 DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
8323 connector->base.id, connector->name, 8325 connector->base.id, connector->name,
8324 encoder->base.id, encoder->name); 8326 encoder->base.id, encoder->name);
8325 8327
8326 mutex_lock(&dev->mode_config.connection_mutex); 8328 drm_modeset_acquire_init(ctx, 0);
8329
8330retry:
8331 ret = drm_modeset_lock(&config->connection_mutex, ctx);
8332 if (ret)
8333 goto fail_unlock;
8327 8334
8328 /* 8335 /*
8329 * Algorithm gets a little messy: 8336 * Algorithm gets a little messy:
@@ -8339,7 +8346,9 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
8339 if (encoder->crtc) { 8346 if (encoder->crtc) {
8340 crtc = encoder->crtc; 8347 crtc = encoder->crtc;
8341 8348
8342 mutex_lock(&crtc->mutex); 8349 ret = drm_modeset_lock(&crtc->mutex, ctx);
8350 if (ret)
8351 goto fail_unlock;
8343 8352
8344 old->dpms_mode = connector->dpms; 8353 old->dpms_mode = connector->dpms;
8345 old->load_detect_temp = false; 8354 old->load_detect_temp = false;
@@ -8367,10 +8376,12 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
8367 */ 8376 */
8368 if (!crtc) { 8377 if (!crtc) {
8369 DRM_DEBUG_KMS("no pipe available for load-detect\n"); 8378 DRM_DEBUG_KMS("no pipe available for load-detect\n");
8370 goto fail_unlock_connector; 8379 goto fail_unlock;
8371 } 8380 }
8372 8381
8373 mutex_lock(&crtc->mutex); 8382 ret = drm_modeset_lock(&crtc->mutex, ctx);
8383 if (ret)
8384 goto fail_unlock;
8374 intel_encoder->new_crtc = to_intel_crtc(crtc); 8385 intel_encoder->new_crtc = to_intel_crtc(crtc);
8375 to_intel_connector(connector)->new_encoder = intel_encoder; 8386 to_intel_connector(connector)->new_encoder = intel_encoder;
8376 8387
@@ -8420,15 +8431,21 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
8420 intel_crtc->new_config = &intel_crtc->config; 8431 intel_crtc->new_config = &intel_crtc->config;
8421 else 8432 else
8422 intel_crtc->new_config = NULL; 8433 intel_crtc->new_config = NULL;
8423 mutex_unlock(&crtc->mutex); 8434fail_unlock:
8424fail_unlock_connector: 8435 if (ret == -EDEADLK) {
8425 mutex_unlock(&dev->mode_config.connection_mutex); 8436 drm_modeset_backoff(ctx);
8437 goto retry;
8438 }
8439
8440 drm_modeset_drop_locks(ctx);
8441 drm_modeset_acquire_fini(ctx);
8426 8442
8427 return false; 8443 return false;
8428} 8444}
8429 8445
8430void intel_release_load_detect_pipe(struct drm_connector *connector, 8446void intel_release_load_detect_pipe(struct drm_connector *connector,
8431 struct intel_load_detect_pipe *old) 8447 struct intel_load_detect_pipe *old,
8448 struct drm_modeset_acquire_ctx *ctx)
8432{ 8449{
8433 struct intel_encoder *intel_encoder = 8450 struct intel_encoder *intel_encoder =
8434 intel_attached_encoder(connector); 8451 intel_attached_encoder(connector);
@@ -8452,8 +8469,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
8452 drm_framebuffer_unreference(old->release_fb); 8469 drm_framebuffer_unreference(old->release_fb);
8453 } 8470 }
8454 8471
8455 mutex_unlock(&crtc->mutex); 8472 goto unlock;
8456 mutex_unlock(&connector->dev->mode_config.connection_mutex);
8457 return; 8473 return;
8458 } 8474 }
8459 8475
@@ -8461,8 +8477,9 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
8461 if (old->dpms_mode != DRM_MODE_DPMS_ON) 8477 if (old->dpms_mode != DRM_MODE_DPMS_ON)
8462 connector->funcs->dpms(connector, old->dpms_mode); 8478 connector->funcs->dpms(connector, old->dpms_mode);
8463 8479
8464 mutex_unlock(&crtc->mutex); 8480unlock:
8465 mutex_unlock(&connector->dev->mode_config.connection_mutex); 8481 drm_modeset_drop_locks(ctx);
8482 drm_modeset_acquire_fini(ctx);
8466} 8483}
8467 8484
8468static int i9xx_pll_refclk(struct drm_device *dev, 8485static int i9xx_pll_refclk(struct drm_device *dev,
@@ -10995,7 +11012,7 @@ enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
10995 struct drm_encoder *encoder = connector->base.encoder; 11012 struct drm_encoder *encoder = connector->base.encoder;
10996 struct drm_device *dev = connector->base.dev; 11013 struct drm_device *dev = connector->base.dev;
10997 11014
10998 WARN_ON(!mutex_is_locked(&dev->mode_config.connection_mutex)); 11015 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
10999 11016
11000 if (!encoder) 11017 if (!encoder)
11001 return INVALID_PIPE; 11018 return INVALID_PIPE;
@@ -11805,6 +11822,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
11805 struct intel_connector *connector; 11822 struct intel_connector *connector;
11806 struct drm_connector *crt = NULL; 11823 struct drm_connector *crt = NULL;
11807 struct intel_load_detect_pipe load_detect_temp; 11824 struct intel_load_detect_pipe load_detect_temp;
11825 struct drm_modeset_acquire_ctx ctx;
11808 11826
11809 /* We can't just switch on the pipe A, we need to set things up with a 11827 /* We can't just switch on the pipe A, we need to set things up with a
11810 * proper mode and output configuration. As a gross hack, enable pipe A 11828 * proper mode and output configuration. As a gross hack, enable pipe A
@@ -11821,8 +11839,8 @@ static void intel_enable_pipe_a(struct drm_device *dev)
11821 if (!crt) 11839 if (!crt)
11822 return; 11840 return;
11823 11841
11824 if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp)) 11842 if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, &ctx))
11825 intel_release_load_detect_pipe(crt, &load_detect_temp); 11843 intel_release_load_detect_pipe(crt, &load_detect_temp, &ctx);
11826 11844
11827 11845
11828} 11846}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index d01bb430b5bc..2d5d9b010073 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1154,7 +1154,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
1154 u32 pp; 1154 u32 pp;
1155 u32 pp_stat_reg, pp_ctrl_reg; 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 if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) { 1159 if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
1160 struct intel_digital_port *intel_dig_port = 1160 struct intel_digital_port *intel_dig_port =
@@ -1191,9 +1191,9 @@ static void edp_panel_vdd_work(struct work_struct *__work)
1191 struct intel_dp, panel_vdd_work); 1191 struct intel_dp, panel_vdd_work);
1192 struct drm_device *dev = intel_dp_to_dev(intel_dp); 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 edp_panel_vdd_off_sync(intel_dp); 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
1199static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) 1199static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
@@ -3666,9 +3666,9 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
3666 drm_encoder_cleanup(encoder); 3666 drm_encoder_cleanup(encoder);
3667 if (is_edp(intel_dp)) { 3667 if (is_edp(intel_dp)) {
3668 cancel_delayed_work_sync(&intel_dp->panel_vdd_work); 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 edp_panel_vdd_off_sync(intel_dp); 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 kfree(intel_dig_port); 3673 kfree(intel_dig_port);
3674} 3674}
@@ -4247,9 +4247,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
4247 drm_dp_aux_unregister(&intel_dp->aux); 4247 drm_dp_aux_unregister(&intel_dp->aux);
4248 if (is_edp(intel_dp)) { 4248 if (is_edp(intel_dp)) {
4249 cancel_delayed_work_sync(&intel_dp->panel_vdd_work); 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 edp_panel_vdd_off_sync(intel_dp); 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 drm_sysfs_connector_remove(connector); 4254 drm_sysfs_connector_remove(connector);
4255 drm_connector_cleanup(connector); 4255 drm_connector_cleanup(connector);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f1d5897c96cd..0de04983501e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -748,9 +748,11 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
748 struct intel_digital_port *dport); 748 struct intel_digital_port *dport);
749bool intel_get_load_detect_pipe(struct drm_connector *connector, 749bool intel_get_load_detect_pipe(struct drm_connector *connector,
750 struct drm_display_mode *mode, 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);
752void intel_release_load_detect_pipe(struct drm_connector *connector, 753void 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);
754int intel_pin_and_fence_fb_obj(struct drm_device *dev, 756int intel_pin_and_fence_fb_obj(struct drm_device *dev,
755 struct drm_i915_gem_object *obj, 757 struct drm_i915_gem_object *obj,
756 struct intel_engine_cs *pipelined); 758 struct intel_engine_cs *pipelined);
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index b812e9d39f38..2e2c71fcc9ed 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -410,7 +410,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
410 if (bclp > 255) 410 if (bclp > 255)
411 return ASLC_BACKLIGHT_FAILED; 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 * Update backlight on all connectors that support backlight (usually 416 * Update backlight on all connectors that support backlight (usually
@@ -421,7 +421,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
421 intel_panel_set_backlight(intel_connector, bclp, 255); 421 intel_panel_set_backlight(intel_connector, bclp, 255);
422 iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv); 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 return 0; 427 return 0;
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index e97ea33e0117..0396d1312b5c 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -688,7 +688,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
688 u32 swidth, swidthsw, sheight, ostride; 688 u32 swidth, swidthsw, sheight, ostride;
689 689
690 BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 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 BUG_ON(!overlay); 692 BUG_ON(!overlay);
693 693
694 ret = intel_overlay_release_old_vid(overlay); 694 ret = intel_overlay_release_old_vid(overlay);
@@ -793,7 +793,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
793 int ret; 793 int ret;
794 794
795 BUG_ON(!mutex_is_locked(&dev->struct_mutex)); 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 ret = intel_overlay_recover_from_interrupt(overlay); 798 ret = intel_overlay_recover_from_interrupt(overlay);
799 if (ret != 0) 799 if (ret != 0)
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index d4d415665475..2e1338a5d488 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -876,12 +876,12 @@ static int intel_backlight_device_update_status(struct backlight_device *bd)
876 struct intel_connector *connector = bl_get_data(bd); 876 struct intel_connector *connector = bl_get_data(bd);
877 struct drm_device *dev = connector->base.dev; 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 DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", 880 DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
881 bd->props.brightness, bd->props.max_brightness); 881 bd->props.brightness, bd->props.max_brightness);
882 intel_panel_set_backlight(connector, bd->props.brightness, 882 intel_panel_set_backlight(connector, bd->props.brightness,
883 bd->props.max_brightness); 883 bd->props.max_brightness);
884 mutex_unlock(&dev->mode_config.connection_mutex); 884 drm_modeset_unlock(&dev->mode_config.connection_mutex);
885 return 0; 885 return 0;
886} 886}
887 887
@@ -893,9 +893,9 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd)
893 int ret; 893 int ret;
894 894
895 intel_runtime_pm_get(dev_priv); 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 ret = intel_panel_get_backlight(connector); 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 intel_runtime_pm_put(dev_priv); 899 intel_runtime_pm_put(dev_priv);
900 900
901 return ret; 901 return ret;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index d6acd6bd0bf0..1b66ddcdfb33 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -55,7 +55,7 @@ static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl
55 int scanline, min, max, vblank_start; 55 int scanline, min, max, vblank_start;
56 DEFINE_WAIT(wait); 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 vblank_start = mode->crtc_vblank_start; 60 vblank_start = mode->crtc_vblank_start;
61 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 61 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 25850a86d70c..67c6c9a2eb1c 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1321,10 +1321,11 @@ intel_tv_detect(struct drm_connector *connector, bool force)
1321 1321
1322 if (force) { 1322 if (force) {
1323 struct intel_load_detect_pipe tmp; 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 type = intel_tv_detect_type(intel_tv, connector); 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 } else 1329 } else
1329 return connector_status_unknown; 1330 return connector_status_unknown;
1330 } else 1331 } else
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index e3c47a8005ff..2d28dc337cfb 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -319,13 +319,13 @@ static void page_flip_worker(struct work_struct *work)
319 struct drm_display_mode *mode = &crtc->mode; 319 struct drm_display_mode *mode = &crtc->mode;
320 struct drm_gem_object *bo; 320 struct drm_gem_object *bo;
321 321
322 mutex_lock(&crtc->mutex); 322 drm_modeset_lock(&crtc->mutex, NULL);
323 omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, 323 omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
324 0, 0, mode->hdisplay, mode->vdisplay, 324 0, 0, mode->hdisplay, mode->vdisplay,
325 crtc->x << 16, crtc->y << 16, 325 crtc->x << 16, crtc->y << 16,
326 mode->hdisplay << 16, mode->vdisplay << 16, 326 mode->hdisplay << 16, mode->vdisplay << 16,
327 vblank_cb, crtc); 327 vblank_cb, crtc);
328 mutex_unlock(&crtc->mutex); 328 drm_modeset_unlock(&crtc->mutex);
329 329
330 bo = omap_framebuffer_bo(crtc->primary->fb, 0); 330 bo = omap_framebuffer_bo(crtc->primary->fb, 0);
331 drm_gem_object_unreference_unlocked(bo); 331 drm_gem_object_unreference_unlocked(bo);
@@ -465,7 +465,7 @@ static void apply_worker(struct work_struct *work)
465 * the callbacks and list modification all serialized 465 * the callbacks and list modification all serialized
466 * with respect to modesetting ioctls from userspace. 466 * with respect to modesetting ioctls from userspace.
467 */ 467 */
468 mutex_lock(&crtc->mutex); 468 drm_modeset_lock(&crtc->mutex, NULL);
469 dispc_runtime_get(); 469 dispc_runtime_get();
470 470
471 /* 471 /*
@@ -510,7 +510,7 @@ static void apply_worker(struct work_struct *work)
510 510
511out: 511out:
512 dispc_runtime_put(); 512 dispc_runtime_put();
513 mutex_unlock(&crtc->mutex); 513 drm_modeset_unlock(&crtc->mutex);
514} 514}
515 515
516int omap_crtc_apply(struct drm_crtc *crtc, 516int omap_crtc_apply(struct drm_crtc *crtc,
@@ -518,7 +518,7 @@ int omap_crtc_apply(struct drm_crtc *crtc,
518{ 518{
519 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 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 /* no need to queue it again if it is already queued: */ 523 /* no need to queue it again if it is already queued: */
524 if (apply->queued) 524 if (apply->queued)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index e7199b454ca0..8f3edc4710f2 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -187,7 +187,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
187 * can do this since the caller in the drm core doesn't check anything 187 * can do this since the caller in the drm core doesn't check anything
188 * which is protected by any looks. 188 * which is protected by any looks.
189 */ 189 */
190 mutex_unlock(&crtc->mutex); 190 drm_modeset_unlock(&crtc->mutex);
191 drm_modeset_lock_all(dev_priv->dev); 191 drm_modeset_lock_all(dev_priv->dev);
192 192
193 /* A lot of the code assumes this */ 193 /* A lot of the code assumes this */
@@ -252,7 +252,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
252 ret = 0; 252 ret = 0;
253out: 253out:
254 drm_modeset_unlock_all(dev_priv->dev); 254 drm_modeset_unlock_all(dev_priv->dev);
255 mutex_lock(&crtc->mutex); 255 drm_modeset_lock(&crtc->mutex, NULL);
256 256
257 return ret; 257 return ret;
258} 258}
@@ -273,7 +273,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
273 * can do this since the caller in the drm core doesn't check anything 273 * can do this since the caller in the drm core doesn't check anything
274 * which is protected by any looks. 274 * which is protected by any looks.
275 */ 275 */
276 mutex_unlock(&crtc->mutex); 276 drm_modeset_unlock(&crtc->mutex);
277 drm_modeset_lock_all(dev_priv->dev); 277 drm_modeset_lock_all(dev_priv->dev);
278 278
279 vmw_cursor_update_position(dev_priv, shown, 279 vmw_cursor_update_position(dev_priv, shown,
@@ -281,7 +281,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
281 du->cursor_y + du->hotspot_y); 281 du->cursor_y + du->hotspot_y);
282 282
283 drm_modeset_unlock_all(dev_priv->dev); 283 drm_modeset_unlock_all(dev_priv->dev);
284 mutex_lock(&crtc->mutex); 284 drm_modeset_lock(&crtc->mutex, NULL);
285 285
286 return 0; 286 return 0;
287} 287}
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 76ccaabd0418..475ca5cf3c20 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1186,11 +1186,6 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)
1186 return ret; 1186 return ret;
1187} 1187}
1188 1188
1189static inline bool drm_modeset_is_locked(struct drm_device *dev)
1190{
1191 return mutex_is_locked(&dev->mode_config.mutex);
1192}
1193
1194static inline bool drm_is_render_client(const struct drm_file *file_priv) 1189static inline bool drm_is_render_client(const struct drm_file *file_priv)
1195{ 1190{
1196 return file_priv->minor->type == DRM_MINOR_RENDER; 1191 return file_priv->minor->type == DRM_MINOR_RENDER;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 6c295df7b0df..a7fac5686915 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -33,6 +33,7 @@
33#include <linux/hdmi.h> 33#include <linux/hdmi.h>
34#include <drm/drm_mode.h> 34#include <drm/drm_mode.h>
35#include <drm/drm_fourcc.h> 35#include <drm/drm_fourcc.h>
36#include <drm/drm_modeset_lock.h>
36 37
37struct drm_device; 38struct drm_device;
38struct drm_mode_set; 39struct drm_mode_set;
@@ -205,6 +206,10 @@ struct drm_property {
205 struct list_head enum_blob_list; 206 struct list_head enum_blob_list;
206}; 207};
207 208
209void drm_modeset_lock_all(struct drm_device *dev);
210void drm_modeset_unlock_all(struct drm_device *dev);
211void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
212
208struct drm_crtc; 213struct drm_crtc;
209struct drm_connector; 214struct drm_connector;
210struct drm_encoder; 215struct drm_encoder;
@@ -280,6 +285,7 @@ struct drm_crtc_funcs {
280 * drm_crtc - central CRTC control structure 285 * drm_crtc - central CRTC control structure
281 * @dev: parent DRM device 286 * @dev: parent DRM device
282 * @head: list management 287 * @head: list management
288 * @mutex: per-CRTC locking
283 * @base: base KMS object for ID tracking etc. 289 * @base: base KMS object for ID tracking etc.
284 * @primary: primary plane for this CRTC 290 * @primary: primary plane for this CRTC
285 * @cursor: cursor plane for this CRTC 291 * @cursor: cursor plane for this CRTC
@@ -314,7 +320,7 @@ struct drm_crtc {
314 * state, ...) and a write lock for everything which can be update 320 * state, ...) and a write lock for everything which can be update
315 * without a full modeset (fb, cursor data, ...) 321 * without a full modeset (fb, cursor data, ...)
316 */ 322 */
317 struct mutex mutex; 323 struct drm_modeset_lock mutex;
318 324
319 struct drm_mode_object base; 325 struct drm_mode_object base;
320 326
@@ -738,7 +744,8 @@ struct drm_mode_group {
738 */ 744 */
739struct drm_mode_config { 745struct drm_mode_config {
740 struct mutex mutex; /* protects configuration (mode lists etc.) */ 746 struct mutex mutex; /* protects configuration (mode lists etc.) */
741 struct mutex connection_mutex; /* protects connector->encoder and encoder->crtc links */ 747 struct drm_modeset_lock connection_mutex; /* protects connector->encoder and encoder->crtc links */
748 struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */
742 struct mutex idr_mutex; /* for IDR management */ 749 struct mutex idr_mutex; /* for IDR management */
743 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ 750 struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
744 /* this is limited to one for now */ 751 /* this is limited to one for now */
@@ -839,10 +846,6 @@ struct drm_prop_enum_list {
839 char *name; 846 char *name;
840}; 847};
841 848
842extern void drm_modeset_lock_all(struct drm_device *dev);
843extern void drm_modeset_unlock_all(struct drm_device *dev);
844extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
845
846extern int drm_crtc_init_with_planes(struct drm_device *dev, 849extern int drm_crtc_init_with_planes(struct drm_device *dev,
847 struct drm_crtc *crtc, 850 struct drm_crtc *crtc,
848 struct drm_plane *primary, 851 struct drm_plane *primary,
diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
new file mode 100644
index 000000000000..402aa7a6a058
--- /dev/null
+++ b/include/drm/drm_modeset_lock.h
@@ -0,0 +1,126 @@
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
29struct 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 */
41struct 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 */
66struct 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
79extern struct ww_class crtc_ww_class;
80
81void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
82 uint32_t flags);
83void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx);
84void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx);
85void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx);
86int 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 */
92static 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 */
102static 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 */
111static inline bool drm_modeset_is_locked(struct drm_modeset_lock *lock)
112{
113 return ww_mutex_is_locked(&lock->mutex);
114}
115
116int drm_modeset_lock(struct drm_modeset_lock *lock,
117 struct drm_modeset_acquire_ctx *ctx);
118int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock,
119 struct drm_modeset_acquire_ctx *ctx);
120void drm_modeset_unlock(struct drm_modeset_lock *lock);
121
122struct drm_device;
123int drm_modeset_lock_all_crtcs(struct drm_device *dev,
124 struct drm_modeset_acquire_ctx *ctx);
125
126#endif /* DRM_MODESET_LOCK_H_ */