diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-09-12 11:07:32 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-09-24 06:09:23 -0400 |
commit | f2b50c1161590c3bcdbf3455fe4c575f1c1bd293 (patch) | |
tree | 6340ffd8dea81f9980e6603a8a08043c8ece149b /drivers/gpu/drm/drm_crtc.c | |
parent | da8f43962bd323813f7215b00b5da48ad766b9b2 (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.c | 51 |
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 | */ |
2266 | static int setplane_internal(struct drm_plane *plane, | 2266 | static 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 | ||
2350 | static 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; |