aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustavo Padovan <gustavo.padovan@collabora.co.uk>2016-11-16 08:00:21 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-11-16 08:36:27 -0500
commitbeaf5af48034c9e2ebb8b2b1fb12dc4d8aeba99e (patch)
tree17d35317f20a49775472e62efe31e1f9bb87289a
parent6d6003c4b613c93973e4e870d83f4bed2ad9ac34 (diff)
drm/fence: add out-fences support
Support DRM out-fences by creating a sync_file with a fence for each CRTC that sets the OUT_FENCE_PTR property. We use the out_fence pointer received in the OUT_FENCE_PTR prop to send the sync_file fd back to userspace. The sync_file and fd are allocated/created before commit, but the fd_install operation only happens after we know that commit succeed. v2: Comment by Rob Clark: - Squash commit that adds DRM_MODE_ATOMIC_OUT_FENCE flag here. Comment by Daniel Vetter: - Add clean up code for out_fences v3: Comments by Daniel Vetter: - create DRM_MODE_ATOMIC_EVENT_MASK - userspace should fill out_fences_ptr with the crtc_ids for which it wants fences back. v4: Create OUT_FENCE_PTR properties and remove old approach. v5: Comments by Brian Starkey: - Remove extra fence_get() in atomic_ioctl() - Check ret before iterating on the crtc_state - check ret before fd_install - set fence_state to NULL at the beginning - check fence_state->out_fence_ptr before put_user() - change order of fput() and put_unused_fd() on failure - Add access_ok() check to the out_fence_ptr received - Rebase after fence -> dma_fence rename - Store out_fence_ptr in the drm_atomic_state - Split crtc_setup_out_fence() - return -1 as out_fence with TEST_ONLY flag v6: Comments by Daniel Vetter - Add prepare/unprepare_crtc_signaling() - move struct drm_out_fence_state to drm_atomic.c - mark get_crtc_fence() as static Comments by Brian Starkey - proper set fence_ptr fence_state array - isolate fence_idx increment - improve error handling v7: Comments by Daniel Vetter - remove prefix from internal functions - make out_fence_ptr an s64 pointer - degrade DRM_INFO to DRM_DEBUG_ATOMIC when put_user fail - fix doc issues - filter out OUT_FENCE_PTR == NULL and do not fail in this case - add complete_crtc_signalling() - krealloc fence_state on demand Comment by Brian Starkey - remove unused crtc_state arg from get_out_fence() v8: Comment by Brian Starkey - cancel events before check for !fence_state - convert a few lefovers u64 types for out_fence_ptr - fix memleak by assign fence_state earlier after realloc - proper accout num_fences in case of error v9: Comment by Brian Starkey - memset last position of fence_state after krealloc Comments by Sean Paul - pass install_fds in complete_crtc_signaling() instead of ret - put_user(-1, fence_ptr) when decoding props v10: Comment by Brian Starkey - remove unneeded num_fences increment on error path - kfree fence_state after installing fences fd v11: rebase against latest drm-misc v12: rebase again against latest drm-misc Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk> Reviewed-by: Brian Starkey <brian.starkey@arm.com> (v10) Reviewed-by: Sean Paul <seanpaul@chromium.org> Tested-by: Robert Foss <robert.foss@collabora.com> (v10) [danvet: Appease checkpatch.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1479301221-13056-1-git-send-email-gustavo@padovan.org
-rw-r--r--drivers/gpu/drm/drm_atomic.c241
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_mode_config.c6
-rw-r--r--include/drm/drm_atomic.h1
-rw-r--r--include/drm/drm_mode_config.h6
5 files changed, 211 insertions, 45 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3ad780ad24f9..b476ec585547 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -290,6 +290,23 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
290} 290}
291EXPORT_SYMBOL(drm_atomic_get_crtc_state); 291EXPORT_SYMBOL(drm_atomic_get_crtc_state);
292 292
293static void set_out_fence_for_crtc(struct drm_atomic_state *state,
294 struct drm_crtc *crtc, s64 __user *fence_ptr)
295{
296 state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
297}
298
299static s64 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
300 struct drm_crtc *crtc)
301{
302 s64 __user *fence_ptr;
303
304 fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
305 state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
306
307 return fence_ptr;
308}
309
293/** 310/**
294 * drm_atomic_set_mode_for_crtc - set mode for CRTC 311 * drm_atomic_set_mode_for_crtc - set mode for CRTC
295 * @state: the CRTC whose incoming state to update 312 * @state: the CRTC whose incoming state to update
@@ -494,6 +511,16 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
494 &replaced); 511 &replaced);
495 state->color_mgmt_changed |= replaced; 512 state->color_mgmt_changed |= replaced;
496 return ret; 513 return ret;
514 } else if (property == config->prop_out_fence_ptr) {
515 s64 __user *fence_ptr = u64_to_user_ptr(val);
516
517 if (!fence_ptr)
518 return 0;
519
520 if (put_user(-1, fence_ptr))
521 return -EFAULT;
522
523 set_out_fence_for_crtc(state->state, crtc, fence_ptr);
497 } else if (crtc->funcs->atomic_set_property) 524 } else if (crtc->funcs->atomic_set_property)
498 return crtc->funcs->atomic_set_property(crtc, state, property, val); 525 return crtc->funcs->atomic_set_property(crtc, state, property, val);
499 else 526 else
@@ -536,6 +563,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
536 *val = (state->ctm) ? state->ctm->base.id : 0; 563 *val = (state->ctm) ? state->ctm->base.id : 0;
537 else if (property == config->gamma_lut_property) 564 else if (property == config->gamma_lut_property)
538 *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; 565 *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
566 else if (property == config->prop_out_fence_ptr)
567 *val = 0;
539 else if (crtc->funcs->atomic_get_property) 568 else if (crtc->funcs->atomic_get_property)
540 return crtc->funcs->atomic_get_property(crtc, state, property, val); 569 return crtc->funcs->atomic_get_property(crtc, state, property, val);
541 else 570 else
@@ -1664,11 +1693,9 @@ int drm_atomic_debugfs_init(struct drm_minor *minor)
1664 */ 1693 */
1665 1694
1666static struct drm_pending_vblank_event *create_vblank_event( 1695static struct drm_pending_vblank_event *create_vblank_event(
1667 struct drm_device *dev, struct drm_file *file_priv, 1696 struct drm_device *dev, uint64_t user_data)
1668 struct dma_fence *fence, uint64_t user_data)
1669{ 1697{
1670 struct drm_pending_vblank_event *e = NULL; 1698 struct drm_pending_vblank_event *e = NULL;
1671 int ret;
1672 1699
1673 e = kzalloc(sizeof *e, GFP_KERNEL); 1700 e = kzalloc(sizeof *e, GFP_KERNEL);
1674 if (!e) 1701 if (!e)
@@ -1678,17 +1705,6 @@ static struct drm_pending_vblank_event *create_vblank_event(
1678 e->event.base.length = sizeof(e->event); 1705 e->event.base.length = sizeof(e->event);
1679 e->event.user_data = user_data; 1706 e->event.user_data = user_data;
1680 1707
1681 if (file_priv) {
1682 ret = drm_event_reserve_init(dev, file_priv, &e->base,
1683 &e->event.base);
1684 if (ret) {
1685 kfree(e);
1686 return NULL;
1687 }
1688 }
1689
1690 e->base.fence = fence;
1691
1692 return e; 1708 return e;
1693} 1709}
1694 1710
@@ -1793,6 +1809,165 @@ void drm_atomic_clean_old_fb(struct drm_device *dev,
1793} 1809}
1794EXPORT_SYMBOL(drm_atomic_clean_old_fb); 1810EXPORT_SYMBOL(drm_atomic_clean_old_fb);
1795 1811
1812static struct dma_fence *get_crtc_fence(struct drm_crtc *crtc)
1813{
1814 struct dma_fence *fence;
1815
1816 fence = kzalloc(sizeof(*fence), GFP_KERNEL);
1817 if (!fence)
1818 return NULL;
1819
1820 dma_fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock,
1821 crtc->fence_context, ++crtc->fence_seqno);
1822
1823 return fence;
1824}
1825
1826struct drm_out_fence_state {
1827 s64 __user *out_fence_ptr;
1828 struct sync_file *sync_file;
1829 int fd;
1830};
1831
1832static int setup_out_fence(struct drm_out_fence_state *fence_state,
1833 struct dma_fence *fence)
1834{
1835 fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
1836 if (fence_state->fd < 0)
1837 return fence_state->fd;
1838
1839 if (put_user(fence_state->fd, fence_state->out_fence_ptr))
1840 return -EFAULT;
1841
1842 fence_state->sync_file = sync_file_create(fence);
1843 if (!fence_state->sync_file)
1844 return -ENOMEM;
1845
1846 return 0;
1847}
1848
1849static int prepare_crtc_signaling(struct drm_device *dev,
1850 struct drm_atomic_state *state,
1851 struct drm_mode_atomic *arg,
1852 struct drm_file *file_priv,
1853 struct drm_out_fence_state **fence_state,
1854 unsigned int *num_fences)
1855{
1856 struct drm_crtc *crtc;
1857 struct drm_crtc_state *crtc_state;
1858 int i, ret;
1859
1860 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
1861 return 0;
1862
1863 for_each_crtc_in_state(state, crtc, crtc_state, i) {
1864 u64 __user *fence_ptr;
1865
1866 fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
1867
1868 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
1869 struct drm_pending_vblank_event *e;
1870
1871 e = create_vblank_event(dev, arg->user_data);
1872 if (!e)
1873 return -ENOMEM;
1874
1875 crtc_state->event = e;
1876 }
1877
1878 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1879 struct drm_pending_vblank_event *e = crtc_state->event;
1880
1881 if (!file_priv)
1882 continue;
1883
1884 ret = drm_event_reserve_init(dev, file_priv, &e->base,
1885 &e->event.base);
1886 if (ret) {
1887 kfree(e);
1888 crtc_state->event = NULL;
1889 return ret;
1890 }
1891 }
1892
1893 if (fence_ptr) {
1894 struct dma_fence *fence;
1895 struct drm_out_fence_state *f;
1896
1897 f = krealloc(*fence_state, sizeof(**fence_state) *
1898 (*num_fences + 1), GFP_KERNEL);
1899 if (!f)
1900 return -ENOMEM;
1901
1902 memset(&f[*num_fences], 0, sizeof(*f));
1903
1904 f[*num_fences].out_fence_ptr = fence_ptr;
1905 *fence_state = f;
1906
1907 fence = get_crtc_fence(crtc);
1908 if (!fence)
1909 return -ENOMEM;
1910
1911 ret = setup_out_fence(&f[(*num_fences)++], fence);
1912 if (ret) {
1913 dma_fence_put(fence);
1914 return ret;
1915 }
1916
1917 crtc_state->event->base.fence = fence;
1918 }
1919 }
1920
1921 return 0;
1922}
1923
1924static void complete_crtc_signaling(struct drm_device *dev,
1925 struct drm_atomic_state *state,
1926 struct drm_out_fence_state *fence_state,
1927 unsigned int num_fences,
1928 bool install_fds)
1929{
1930 struct drm_crtc *crtc;
1931 struct drm_crtc_state *crtc_state;
1932 int i;
1933
1934 if (install_fds) {
1935 for (i = 0; i < num_fences; i++)
1936 fd_install(fence_state[i].fd,
1937 fence_state[i].sync_file->file);
1938
1939 kfree(fence_state);
1940 return;
1941 }
1942
1943 for_each_crtc_in_state(state, crtc, crtc_state, i) {
1944 /*
1945 * TEST_ONLY and PAGE_FLIP_EVENT are mutually
1946 * exclusive, if they weren't, this code should be
1947 * called on success for TEST_ONLY too.
1948 */
1949 if (crtc_state->event)
1950 drm_event_cancel_free(dev, &crtc_state->event->base);
1951 }
1952
1953 if (!fence_state)
1954 return;
1955
1956 for (i = 0; i < num_fences; i++) {
1957 if (fence_state[i].sync_file)
1958 fput(fence_state[i].sync_file->file);
1959 if (fence_state[i].fd >= 0)
1960 put_unused_fd(fence_state[i].fd);
1961
1962 /* If this fails log error to the user */
1963 if (fence_state[i].out_fence_ptr &&
1964 put_user(-1, fence_state[i].out_fence_ptr))
1965 DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n");
1966 }
1967
1968 kfree(fence_state);
1969}
1970
1796int drm_mode_atomic_ioctl(struct drm_device *dev, 1971int drm_mode_atomic_ioctl(struct drm_device *dev,
1797 void *data, struct drm_file *file_priv) 1972 void *data, struct drm_file *file_priv)
1798{ 1973{
@@ -1805,11 +1980,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
1805 struct drm_atomic_state *state; 1980 struct drm_atomic_state *state;
1806 struct drm_modeset_acquire_ctx ctx; 1981 struct drm_modeset_acquire_ctx ctx;
1807 struct drm_plane *plane; 1982 struct drm_plane *plane;
1808 struct drm_crtc *crtc; 1983 struct drm_out_fence_state *fence_state = NULL;
1809 struct drm_crtc_state *crtc_state;
1810 unsigned plane_mask; 1984 unsigned plane_mask;
1811 int ret = 0; 1985 int ret = 0;
1812 unsigned int i, j; 1986 unsigned int i, j, num_fences = 0;
1813 1987
1814 /* disallow for drivers not supporting atomic: */ 1988 /* disallow for drivers not supporting atomic: */
1815 if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) 1989 if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
@@ -1924,20 +2098,10 @@ retry:
1924 drm_mode_object_unreference(obj); 2098 drm_mode_object_unreference(obj);
1925 } 2099 }
1926 2100
1927 if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { 2101 ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state,
1928 for_each_crtc_in_state(state, crtc, crtc_state, i) { 2102 &num_fences);
1929 struct drm_pending_vblank_event *e; 2103 if (ret)
1930 2104 goto out;
1931 e = create_vblank_event(dev, file_priv, NULL,
1932 arg->user_data);
1933 if (!e) {
1934 ret = -ENOMEM;
1935 goto out;
1936 }
1937
1938 crtc_state->event = e;
1939 }
1940 }
1941 2105
1942 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { 2106 if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
1943 /* 2107 /*
@@ -1957,20 +2121,7 @@ retry:
1957out: 2121out:
1958 drm_atomic_clean_old_fb(dev, plane_mask, ret); 2122 drm_atomic_clean_old_fb(dev, plane_mask, ret);
1959 2123
1960 if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { 2124 complete_crtc_signaling(dev, state, fence_state, num_fences, !ret);
1961 /*
1962 * TEST_ONLY and PAGE_FLIP_EVENT are mutually exclusive,
1963 * if they weren't, this code should be called on success
1964 * for TEST_ONLY too.
1965 */
1966
1967 for_each_crtc_in_state(state, crtc, crtc_state, i) {
1968 if (!crtc_state->event)
1969 continue;
1970
1971 drm_event_cancel_free(dev, &crtc_state->event->base);
1972 }
1973 }
1974 2125
1975 if (ret == -EDEADLK) { 2126 if (ret == -EDEADLK) {
1976 drm_atomic_state_clear(state); 2127 drm_atomic_state_clear(state);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index dbfae422241e..90931e039731 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -267,6 +267,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
267 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { 267 if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
268 drm_object_attach_property(&crtc->base, config->prop_active, 0); 268 drm_object_attach_property(&crtc->base, config->prop_active, 0);
269 drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); 269 drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
270 drm_object_attach_property(&crtc->base,
271 config->prop_out_fence_ptr, 0);
270 } 272 }
271 273
272 return 0; 274 return 0;
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 8bee2addf7b4..2735a5847ffa 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -314,6 +314,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
314 return -ENOMEM; 314 return -ENOMEM;
315 dev->mode_config.prop_in_fence_fd = prop; 315 dev->mode_config.prop_in_fence_fd = prop;
316 316
317 prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
318 "OUT_FENCE_PTR", 0, U64_MAX);
319 if (!prop)
320 return -ENOMEM;
321 dev->mode_config.prop_out_fence_ptr = prop;
322
317 prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, 323 prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
318 "CRTC_ID", DRM_MODE_OBJECT_CRTC); 324 "CRTC_ID", DRM_MODE_OBJECT_CRTC);
319 if (!prop) 325 if (!prop)
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 331bb100b718..c0eaec70a203 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -144,6 +144,7 @@ struct __drm_crtcs_state {
144 struct drm_crtc *ptr; 144 struct drm_crtc *ptr;
145 struct drm_crtc_state *state; 145 struct drm_crtc_state *state;
146 struct drm_crtc_commit *commit; 146 struct drm_crtc_commit *commit;
147 s64 __user *out_fence_ptr;
147}; 148};
148 149
149struct __drm_connnectors_state { 150struct __drm_connnectors_state {
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index c6754ccefe2b..bf9991b20611 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -486,6 +486,12 @@ struct drm_mode_config {
486 */ 486 */
487 struct drm_property *prop_in_fence_fd; 487 struct drm_property *prop_in_fence_fd;
488 /** 488 /**
489 * @prop_out_fence_ptr: Sync File fd pointer representing the
490 * outgoing fences for a CRTC. Userspace should provide a pointer to a
491 * value of type s64, and then cast that pointer to u64.
492 */
493 struct drm_property *prop_out_fence_ptr;
494 /**
489 * @prop_crtc_id: Default atomic plane property to specify the 495 * @prop_crtc_id: Default atomic plane property to specify the
490 * &drm_crtc. 496 * &drm_crtc.
491 */ 497 */