diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d4f8fa5b3c18..64ef12079528 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -445,6 +445,12 @@ static void drm_framebuffer_free_bug(struct kref *kref) | |||
445 | BUG(); | 445 | BUG(); |
446 | } | 446 | } |
447 | 447 | ||
448 | static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) | ||
449 | { | ||
450 | DRM_DEBUG("FB ID: %d\n", fb->base.id); | ||
451 | kref_put(&fb->refcount, drm_framebuffer_free_bug); | ||
452 | } | ||
453 | |||
448 | /* dev->mode_config.fb_lock must be held! */ | 454 | /* dev->mode_config.fb_lock must be held! */ |
449 | static void __drm_framebuffer_unregister(struct drm_device *dev, | 455 | static void __drm_framebuffer_unregister(struct drm_device *dev, |
450 | struct drm_framebuffer *fb) | 456 | struct drm_framebuffer *fb) |
@@ -455,7 +461,7 @@ static void __drm_framebuffer_unregister(struct drm_device *dev, | |||
455 | 461 | ||
456 | fb->base.id = 0; | 462 | fb->base.id = 0; |
457 | 463 | ||
458 | kref_put(&fb->refcount, drm_framebuffer_free_bug); | 464 | __drm_framebuffer_unreference(fb); |
459 | } | 465 | } |
460 | 466 | ||
461 | /** | 467 | /** |
@@ -544,6 +550,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) | |||
544 | if (ret) | 550 | if (ret) |
545 | DRM_ERROR("failed to disable plane with busy fb\n"); | 551 | DRM_ERROR("failed to disable plane with busy fb\n"); |
546 | /* disconnect the plane from the fb and crtc: */ | 552 | /* disconnect the plane from the fb and crtc: */ |
553 | __drm_framebuffer_unreference(plane->fb); | ||
547 | plane->fb = NULL; | 554 | plane->fb = NULL; |
548 | plane->crtc = NULL; | 555 | plane->crtc = NULL; |
549 | } | 556 | } |
@@ -1850,7 +1857,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1850 | struct drm_mode_object *obj; | 1857 | struct drm_mode_object *obj; |
1851 | struct drm_plane *plane; | 1858 | struct drm_plane *plane; |
1852 | struct drm_crtc *crtc; | 1859 | struct drm_crtc *crtc; |
1853 | struct drm_framebuffer *fb; | 1860 | struct drm_framebuffer *fb = NULL, *old_fb = NULL; |
1854 | int ret = 0; | 1861 | int ret = 0; |
1855 | unsigned int fb_width, fb_height; | 1862 | unsigned int fb_width, fb_height; |
1856 | int i; | 1863 | int i; |
@@ -1858,8 +1865,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1858 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | 1865 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1859 | return -EINVAL; | 1866 | return -EINVAL; |
1860 | 1867 | ||
1861 | drm_modeset_lock_all(dev); | ||
1862 | |||
1863 | /* | 1868 | /* |
1864 | * First, find the plane, crtc, and fb objects. If not available, | 1869 | * First, find the plane, crtc, and fb objects. If not available, |
1865 | * we don't bother to call the driver. | 1870 | * we don't bother to call the driver. |
@@ -1869,16 +1874,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1869 | if (!obj) { | 1874 | if (!obj) { |
1870 | DRM_DEBUG_KMS("Unknown plane ID %d\n", | 1875 | DRM_DEBUG_KMS("Unknown plane ID %d\n", |
1871 | plane_req->plane_id); | 1876 | plane_req->plane_id); |
1872 | ret = -ENOENT; | 1877 | return -ENOENT; |
1873 | goto out; | ||
1874 | } | 1878 | } |
1875 | plane = obj_to_plane(obj); | 1879 | plane = obj_to_plane(obj); |
1876 | 1880 | ||
1877 | /* No fb means shut it down */ | 1881 | /* No fb means shut it down */ |
1878 | if (!plane_req->fb_id) { | 1882 | if (!plane_req->fb_id) { |
1883 | drm_modeset_lock_all(dev); | ||
1884 | old_fb = plane->fb; | ||
1879 | plane->funcs->disable_plane(plane); | 1885 | plane->funcs->disable_plane(plane); |
1880 | plane->crtc = NULL; | 1886 | plane->crtc = NULL; |
1881 | plane->fb = NULL; | 1887 | plane->fb = NULL; |
1888 | drm_modeset_unlock_all(dev); | ||
1882 | goto out; | 1889 | goto out; |
1883 | } | 1890 | } |
1884 | 1891 | ||
@@ -1899,8 +1906,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1899 | ret = -ENOENT; | 1906 | ret = -ENOENT; |
1900 | goto out; | 1907 | goto out; |
1901 | } | 1908 | } |
1902 | /* fb is protect by the mode_config lock, so drop the ref immediately */ | ||
1903 | drm_framebuffer_unreference(fb); | ||
1904 | 1909 | ||
1905 | /* Check whether this plane supports the fb pixel format. */ | 1910 | /* Check whether this plane supports the fb pixel format. */ |
1906 | for (i = 0; i < plane->format_count; i++) | 1911 | for (i = 0; i < plane->format_count; i++) |
@@ -1946,18 +1951,25 @@ int drm_mode_setplane(struct drm_device *dev, void *data, | |||
1946 | goto out; | 1951 | goto out; |
1947 | } | 1952 | } |
1948 | 1953 | ||
1954 | drm_modeset_lock_all(dev); | ||
1949 | ret = plane->funcs->update_plane(plane, crtc, fb, | 1955 | ret = plane->funcs->update_plane(plane, crtc, fb, |
1950 | plane_req->crtc_x, plane_req->crtc_y, | 1956 | plane_req->crtc_x, plane_req->crtc_y, |
1951 | plane_req->crtc_w, plane_req->crtc_h, | 1957 | plane_req->crtc_w, plane_req->crtc_h, |
1952 | plane_req->src_x, plane_req->src_y, | 1958 | plane_req->src_x, plane_req->src_y, |
1953 | plane_req->src_w, plane_req->src_h); | 1959 | plane_req->src_w, plane_req->src_h); |
1954 | if (!ret) { | 1960 | if (!ret) { |
1961 | old_fb = plane->fb; | ||
1962 | fb = NULL; | ||
1955 | plane->crtc = crtc; | 1963 | plane->crtc = crtc; |
1956 | plane->fb = fb; | 1964 | plane->fb = fb; |
1957 | } | 1965 | } |
1966 | drm_modeset_unlock_all(dev); | ||
1958 | 1967 | ||
1959 | out: | 1968 | out: |
1960 | drm_modeset_unlock_all(dev); | 1969 | if (fb) |
1970 | drm_framebuffer_unreference(fb); | ||
1971 | if (old_fb) | ||
1972 | drm_framebuffer_unreference(old_fb); | ||
1961 | 1973 | ||
1962 | return ret; | 1974 | return ret; |
1963 | } | 1975 | } |