Skip to content

Commit beaf5af

Browse files
Gustavo Padovandanvet
authored andcommitted
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 <[email protected]> Reviewed-by: Brian Starkey <[email protected]> (v10) Reviewed-by: Sean Paul <[email protected]> Tested-by: Robert Foss <[email protected]> (v10) [danvet: Appease checkpatch.] Signed-off-by: Daniel Vetter <[email protected]> Link: http://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 6d6003c commit beaf5af

File tree

5 files changed

+211
-45
lines changed

5 files changed

+211
-45
lines changed

drivers/gpu/drm/drm_atomic.c

Lines changed: 196 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,23 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
290290
}
291291
EXPORT_SYMBOL(drm_atomic_get_crtc_state);
292292

293+
static 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+
299+
static 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+
293310
/**
294311
* drm_atomic_set_mode_for_crtc - set mode for CRTC
295312
* @state: the CRTC whose incoming state to update
@@ -494,6 +511,16 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
494511
&replaced);
495512
state->color_mgmt_changed |= replaced;
496513
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);
497524
} else if (crtc->funcs->atomic_set_property)
498525
return crtc->funcs->atomic_set_property(crtc, state, property, val);
499526
else
@@ -536,6 +563,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
536563
*val = (state->ctm) ? state->ctm->base.id : 0;
537564
else if (property == config->gamma_lut_property)
538565
*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
566+
else if (property == config->prop_out_fence_ptr)
567+
*val = 0;
539568
else if (crtc->funcs->atomic_get_property)
540569
return crtc->funcs->atomic_get_property(crtc, state, property, val);
541570
else
@@ -1664,11 +1693,9 @@ int drm_atomic_debugfs_init(struct drm_minor *minor)
16641693
*/
16651694

16661695
static struct drm_pending_vblank_event *create_vblank_event(
1667-
struct drm_device *dev, struct drm_file *file_priv,
1668-
struct dma_fence *fence, uint64_t user_data)
1696+
struct drm_device *dev, uint64_t user_data)
16691697
{
16701698
struct drm_pending_vblank_event *e = NULL;
1671-
int ret;
16721699

16731700
e = kzalloc(sizeof *e, GFP_KERNEL);
16741701
if (!e)
@@ -1678,17 +1705,6 @@ static struct drm_pending_vblank_event *create_vblank_event(
16781705
e->event.base.length = sizeof(e->event);
16791706
e->event.user_data = user_data;
16801707

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-
16921708
return e;
16931709
}
16941710

@@ -1793,6 +1809,165 @@ void drm_atomic_clean_old_fb(struct drm_device *dev,
17931809
}
17941810
EXPORT_SYMBOL(drm_atomic_clean_old_fb);
17951811

1812+
static 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+
1826+
struct drm_out_fence_state {
1827+
s64 __user *out_fence_ptr;
1828+
struct sync_file *sync_file;
1829+
int fd;
1830+
};
1831+
1832+
static 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+
1849+
static 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+
1924+
static 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+
17961971
int drm_mode_atomic_ioctl(struct drm_device *dev,
17971972
void *data, struct drm_file *file_priv)
17981973
{
@@ -1805,11 +1980,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
18051980
struct drm_atomic_state *state;
18061981
struct drm_modeset_acquire_ctx ctx;
18071982
struct drm_plane *plane;
1808-
struct drm_crtc *crtc;
1809-
struct drm_crtc_state *crtc_state;
1983+
struct drm_out_fence_state *fence_state = NULL;
18101984
unsigned plane_mask;
18111985
int ret = 0;
1812-
unsigned int i, j;
1986+
unsigned int i, j, num_fences = 0;
18131987

18141988
/* disallow for drivers not supporting atomic: */
18151989
if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
@@ -1924,20 +2098,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
19242098
drm_mode_object_unreference(obj);
19252099
}
19262100

1927-
if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
1928-
for_each_crtc_in_state(state, crtc, crtc_state, i) {
1929-
struct drm_pending_vblank_event *e;
1930-
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-
}
2101+
ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state,
2102+
&num_fences);
2103+
if (ret)
2104+
goto out;
19412105

19422106
if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
19432107
/*
@@ -1957,20 +2121,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
19572121
out:
19582122
drm_atomic_clean_old_fb(dev, plane_mask, ret);
19592123

1960-
if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
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-
}
2124+
complete_crtc_signaling(dev, state, fence_state, num_fences, !ret);
19742125

19752126
if (ret == -EDEADLK) {
19762127
drm_atomic_state_clear(state);

drivers/gpu/drm/drm_crtc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
267267
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
268268
drm_object_attach_property(&crtc->base, config->prop_active, 0);
269269
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);
270272
}
271273

272274
return 0;

drivers/gpu/drm/drm_mode_config.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
314314
return -ENOMEM;
315315
dev->mode_config.prop_in_fence_fd = prop;
316316

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+
317323
prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
318324
"CRTC_ID", DRM_MODE_OBJECT_CRTC);
319325
if (!prop)

include/drm/drm_atomic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct __drm_crtcs_state {
144144
struct drm_crtc *ptr;
145145
struct drm_crtc_state *state;
146146
struct drm_crtc_commit *commit;
147+
s64 __user *out_fence_ptr;
147148
};
148149

149150
struct __drm_connnectors_state {

include/drm/drm_mode_config.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,12 @@ struct drm_mode_config {
485485
* for a Plane.
486486
*/
487487
struct drm_property *prop_in_fence_fd;
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;
488494
/**
489495
* @prop_crtc_id: Default atomic plane property to specify the
490496
* &drm_crtc.

0 commit comments

Comments
 (0)