aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2014-09-12 11:07:32 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-09-24 06:09:23 -0400
commitf2b50c1161590c3bcdbf3455fe4c575f1c1bd293 (patch)
tree6340ffd8dea81f9980e6603a8a08043c8ece149b /drivers/gpu/drm/drm_crtc.c
parentda8f43962bd323813f7215b00b5da48ad766b9b2 (diff)
drm: Fixup locking for universal cursor planes
Bunch of things amiss: - Updating crtc->cursor_x/y was done without any locking. Spotted by David Herrmann. - Dereferencing crtc->cursor->fb was using the wrong lock, should take the crtc lock. - Grabbing _all_ modeset locks torpedoes the reason why we added fine-grained locks originally: Cursor updates shouldn't stall on background stuff like probing outputs. Best is to just grab the crtc lock around everything and drop all the other locking. The only issue is that we can't switch planes between crtcs with that, so make sure that never happens when someone uses universal plane helpers. This shouldn't be a possible regression ever since legacy ioctls also only grabbed the crtc lock, so switching crtcs was never possible for the underlying plane object. And i915 (the only user of universal cursors thus far) has fixed cursor->crtc links. Cc: David Herrmann <dh.herrmann@gmail.com> Cc: Pallavi G<pallavi.g@intel.com> Cc: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Matt Roper <matthew.d.roper@intel.com> Tested-by: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c51
1 files changed, 34 insertions, 17 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index ecd4e0b4c525..b7021069b078 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2263,21 +2263,19 @@ out:
2263 * 2263 *
2264 * src_{x,y,w,h} are provided in 16.16 fixed point format 2264 * src_{x,y,w,h} are provided in 16.16 fixed point format
2265 */ 2265 */
2266static int setplane_internal(struct drm_plane *plane, 2266static int __setplane_internal(struct drm_plane *plane,
2267 struct drm_crtc *crtc, 2267 struct drm_crtc *crtc,
2268 struct drm_framebuffer *fb, 2268 struct drm_framebuffer *fb,
2269 int32_t crtc_x, int32_t crtc_y, 2269 int32_t crtc_x, int32_t crtc_y,
2270 uint32_t crtc_w, uint32_t crtc_h, 2270 uint32_t crtc_w, uint32_t crtc_h,
2271 /* src_{x,y,w,h} values are 16.16 fixed point */ 2271 /* src_{x,y,w,h} values are 16.16 fixed point */
2272 uint32_t src_x, uint32_t src_y, 2272 uint32_t src_x, uint32_t src_y,
2273 uint32_t src_w, uint32_t src_h) 2273 uint32_t src_w, uint32_t src_h)
2274{ 2274{
2275 struct drm_device *dev = plane->dev;
2276 int ret = 0; 2275 int ret = 0;
2277 unsigned int fb_width, fb_height; 2276 unsigned int fb_width, fb_height;
2278 int i; 2277 int i;
2279 2278
2280 drm_modeset_lock_all(dev);
2281 /* No fb means shut it down */ 2279 /* No fb means shut it down */
2282 if (!fb) { 2280 if (!fb) {
2283 plane->old_fb = plane->fb; 2281 plane->old_fb = plane->fb;
@@ -2345,10 +2343,28 @@ out:
2345 if (plane->old_fb) 2343 if (plane->old_fb)
2346 drm_framebuffer_unreference(plane->old_fb); 2344 drm_framebuffer_unreference(plane->old_fb);
2347 plane->old_fb = NULL; 2345 plane->old_fb = NULL;
2348 drm_modeset_unlock_all(dev);
2349 2346
2350 return ret; 2347 return ret;
2348}
2351 2349
2350static int setplane_internal(struct drm_plane *plane,
2351 struct drm_crtc *crtc,
2352 struct drm_framebuffer *fb,
2353 int32_t crtc_x, int32_t crtc_y,
2354 uint32_t crtc_w, uint32_t crtc_h,
2355 /* src_{x,y,w,h} values are 16.16 fixed point */
2356 uint32_t src_x, uint32_t src_y,
2357 uint32_t src_w, uint32_t src_h)
2358{
2359 int ret;
2360
2361 drm_modeset_lock_all(plane->dev);
2362 ret = __setplane_internal(plane, crtc, fb,
2363 crtc_x, crtc_y, crtc_w, crtc_h,
2364 src_x, src_y, src_w, src_h);
2365 drm_modeset_unlock_all(plane->dev);
2366
2367 return ret;
2352} 2368}
2353 2369
2354/** 2370/**
@@ -2714,6 +2730,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
2714 int ret = 0; 2730 int ret = 0;
2715 2731
2716 BUG_ON(!crtc->cursor); 2732 BUG_ON(!crtc->cursor);
2733 WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL);
2717 2734
2718 /* 2735 /*
2719 * Obtain fb we'll be using (either new or existing) and take an extra 2736 * Obtain fb we'll be using (either new or existing) and take an extra
@@ -2733,11 +2750,9 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
2733 fb = NULL; 2750 fb = NULL;
2734 } 2751 }
2735 } else { 2752 } else {
2736 mutex_lock(&dev->mode_config.mutex);
2737 fb = crtc->cursor->fb; 2753 fb = crtc->cursor->fb;
2738 if (fb) 2754 if (fb)
2739 drm_framebuffer_reference(fb); 2755 drm_framebuffer_reference(fb);
2740 mutex_unlock(&dev->mode_config.mutex);
2741 } 2756 }
2742 2757
2743 if (req->flags & DRM_MODE_CURSOR_MOVE) { 2758 if (req->flags & DRM_MODE_CURSOR_MOVE) {
@@ -2759,7 +2774,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
2759 * setplane_internal will take care of deref'ing either the old or new 2774 * setplane_internal will take care of deref'ing either the old or new
2760 * framebuffer depending on success. 2775 * framebuffer depending on success.
2761 */ 2776 */
2762 ret = setplane_internal(crtc->cursor, crtc, fb, 2777 ret = __setplane_internal(crtc->cursor, crtc, fb,
2763 crtc_x, crtc_y, crtc_w, crtc_h, 2778 crtc_x, crtc_y, crtc_w, crtc_h,
2764 0, 0, src_w, src_h); 2779 0, 0, src_w, src_h);
2765 2780
@@ -2795,10 +2810,12 @@ static int drm_mode_cursor_common(struct drm_device *dev,
2795 * If this crtc has a universal cursor plane, call that plane's update 2810 * If this crtc has a universal cursor plane, call that plane's update
2796 * handler rather than using legacy cursor handlers. 2811 * handler rather than using legacy cursor handlers.
2797 */ 2812 */
2798 if (crtc->cursor)
2799 return drm_mode_cursor_universal(crtc, req, file_priv);
2800
2801 drm_modeset_lock_crtc(crtc); 2813 drm_modeset_lock_crtc(crtc);
2814 if (crtc->cursor) {
2815 ret = drm_mode_cursor_universal(crtc, req, file_priv);
2816 goto out;
2817 }
2818
2802 if (req->flags & DRM_MODE_CURSOR_BO) { 2819 if (req->flags & DRM_MODE_CURSOR_BO) {
2803 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { 2820 if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
2804 ret = -ENXIO; 2821 ret = -ENXIO;