diff options
author | Brian Starkey <brian.starkey@arm.com> | 2017-03-29 12:42:33 -0400 |
---|---|---|
committer | Liviu Dudau <Liviu.Dudau@arm.com> | 2018-06-20 10:29:18 -0400 |
commit | b13cc8dd588434e2aec781e6d12224e4c408ac18 (patch) | |
tree | c202a3e17b01d1db38cebd680dd7d5cdc0f641cf | |
parent | 935774cd71fe604cc8ed24adcb507d7784255672 (diff) |
drm: writeback: Add out-fences for writeback connectors
Add the WRITEBACK_OUT_FENCE_PTR property to writeback connectors, to
enable userspace to get a fence which will signal once the writeback is
complete. It is not allowed to request an out-fence without a
framebuffer attached to the connector.
A timeline is added to drm_writeback_connector for use by the writeback
out-fences.
In the case of a commit failure or DRM_MODE_ATOMIC_TEST_ONLY, the fence
is set to -1.
Changes from v2:
- Rebase onto Gustavo Padovan's v9 explicit sync series
- Change out_fence_ptr type to s32 __user *
- Set *out_fence_ptr to -1 in drm_atomic_connector_set_property
- Store fence in drm_writeback_job
Gustavo Padovan:
- Move out_fence_ptr out of connector_state
- Signal fence from drm_writeback_signal_completion instead of
in driver directly
Changes from v3:
- Rebase onto commit 7e9081c5aac7 ("drm/fence: fix memory overwrite
when setting out_fence fd") (change out_fence_ptr to s32 __user *,
for real this time.)
- Update documentation around WRITEBACK_OUT_FENCE_PTR
Signed-off-by: Brian Starkey <brian.starkey@arm.com>
[rebased and fixed conflicts]
Signed-off-by: Mihail Atanassov <mihail.atanassov@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Link: https://patchwork.freedesktop.org/patch/229036/
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 99 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_writeback.c | 109 | ||||
-rw-r--r-- | include/drm/drm_atomic.h | 8 | ||||
-rw-r--r-- | include/drm/drm_connector.h | 8 | ||||
-rw-r--r-- | include/drm/drm_mode_config.h | 8 | ||||
-rw-r--r-- | include/drm/drm_writeback.h | 41 |
6 files changed, 257 insertions, 16 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3e53d6e5c340..115719059434 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c | |||
@@ -318,6 +318,35 @@ static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, | |||
318 | return fence_ptr; | 318 | return fence_ptr; |
319 | } | 319 | } |
320 | 320 | ||
321 | static int set_out_fence_for_connector(struct drm_atomic_state *state, | ||
322 | struct drm_connector *connector, | ||
323 | s32 __user *fence_ptr) | ||
324 | { | ||
325 | unsigned int index = drm_connector_index(connector); | ||
326 | |||
327 | if (!fence_ptr) | ||
328 | return 0; | ||
329 | |||
330 | if (put_user(-1, fence_ptr)) | ||
331 | return -EFAULT; | ||
332 | |||
333 | state->connectors[index].out_fence_ptr = fence_ptr; | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, | ||
339 | struct drm_connector *connector) | ||
340 | { | ||
341 | unsigned int index = drm_connector_index(connector); | ||
342 | s32 __user *fence_ptr; | ||
343 | |||
344 | fence_ptr = state->connectors[index].out_fence_ptr; | ||
345 | state->connectors[index].out_fence_ptr = NULL; | ||
346 | |||
347 | return fence_ptr; | ||
348 | } | ||
349 | |||
321 | /** | 350 | /** |
322 | * drm_atomic_set_mode_for_crtc - set mode for CRTC | 351 | * drm_atomic_set_mode_for_crtc - set mode for CRTC |
323 | * @state: the CRTC whose incoming state to update | 352 | * @state: the CRTC whose incoming state to update |
@@ -727,6 +756,12 @@ static int drm_atomic_connector_check(struct drm_connector *connector, | |||
727 | return -EINVAL; | 756 | return -EINVAL; |
728 | } | 757 | } |
729 | 758 | ||
759 | if (writeback_job->out_fence && !writeback_job->fb) { | ||
760 | DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] requesting out-fence without framebuffer\n", | ||
761 | connector->base.id, connector->name); | ||
762 | return -EINVAL; | ||
763 | } | ||
764 | |||
730 | return 0; | 765 | return 0; |
731 | } | 766 | } |
732 | 767 | ||
@@ -1367,6 +1402,11 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, | |||
1367 | if (fb) | 1402 | if (fb) |
1368 | drm_framebuffer_put(fb); | 1403 | drm_framebuffer_put(fb); |
1369 | return ret; | 1404 | return ret; |
1405 | } else if (property == config->writeback_out_fence_ptr_property) { | ||
1406 | s32 __user *fence_ptr = u64_to_user_ptr(val); | ||
1407 | |||
1408 | return set_out_fence_for_connector(state->state, connector, | ||
1409 | fence_ptr); | ||
1370 | } else if (connector->funcs->atomic_set_property) { | 1410 | } else if (connector->funcs->atomic_set_property) { |
1371 | return connector->funcs->atomic_set_property(connector, | 1411 | return connector->funcs->atomic_set_property(connector, |
1372 | state, property, val); | 1412 | state, property, val); |
@@ -1456,6 +1496,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector, | |||
1456 | } else if (property == config->writeback_fb_id_property) { | 1496 | } else if (property == config->writeback_fb_id_property) { |
1457 | /* Writeback framebuffer is one-shot, write and forget */ | 1497 | /* Writeback framebuffer is one-shot, write and forget */ |
1458 | *val = 0; | 1498 | *val = 0; |
1499 | } else if (property == config->writeback_out_fence_ptr_property) { | ||
1500 | *val = 0; | ||
1459 | } else if (connector->funcs->atomic_get_property) { | 1501 | } else if (connector->funcs->atomic_get_property) { |
1460 | return connector->funcs->atomic_get_property(connector, | 1502 | return connector->funcs->atomic_get_property(connector, |
1461 | state, property, val); | 1503 | state, property, val); |
@@ -2292,7 +2334,7 @@ static int setup_out_fence(struct drm_out_fence_state *fence_state, | |||
2292 | return 0; | 2334 | return 0; |
2293 | } | 2335 | } |
2294 | 2336 | ||
2295 | static int prepare_crtc_signaling(struct drm_device *dev, | 2337 | static int prepare_signaling(struct drm_device *dev, |
2296 | struct drm_atomic_state *state, | 2338 | struct drm_atomic_state *state, |
2297 | struct drm_mode_atomic *arg, | 2339 | struct drm_mode_atomic *arg, |
2298 | struct drm_file *file_priv, | 2340 | struct drm_file *file_priv, |
@@ -2301,6 +2343,8 @@ static int prepare_crtc_signaling(struct drm_device *dev, | |||
2301 | { | 2343 | { |
2302 | struct drm_crtc *crtc; | 2344 | struct drm_crtc *crtc; |
2303 | struct drm_crtc_state *crtc_state; | 2345 | struct drm_crtc_state *crtc_state; |
2346 | struct drm_connector *conn; | ||
2347 | struct drm_connector_state *conn_state; | ||
2304 | int i, c = 0, ret; | 2348 | int i, c = 0, ret; |
2305 | 2349 | ||
2306 | if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) | 2350 | if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) |
@@ -2366,6 +2410,43 @@ static int prepare_crtc_signaling(struct drm_device *dev, | |||
2366 | c++; | 2410 | c++; |
2367 | } | 2411 | } |
2368 | 2412 | ||
2413 | for_each_new_connector_in_state(state, conn, conn_state, i) { | ||
2414 | struct drm_writeback_job *job; | ||
2415 | struct drm_out_fence_state *f; | ||
2416 | struct dma_fence *fence; | ||
2417 | s32 __user *fence_ptr; | ||
2418 | |||
2419 | fence_ptr = get_out_fence_for_connector(state, conn); | ||
2420 | if (!fence_ptr) | ||
2421 | continue; | ||
2422 | |||
2423 | job = drm_atomic_get_writeback_job(conn_state); | ||
2424 | if (!job) | ||
2425 | return -ENOMEM; | ||
2426 | |||
2427 | f = krealloc(*fence_state, sizeof(**fence_state) * | ||
2428 | (*num_fences + 1), GFP_KERNEL); | ||
2429 | if (!f) | ||
2430 | return -ENOMEM; | ||
2431 | |||
2432 | memset(&f[*num_fences], 0, sizeof(*f)); | ||
2433 | |||
2434 | f[*num_fences].out_fence_ptr = fence_ptr; | ||
2435 | *fence_state = f; | ||
2436 | |||
2437 | fence = drm_writeback_get_out_fence((struct drm_writeback_connector *)conn); | ||
2438 | if (!fence) | ||
2439 | return -ENOMEM; | ||
2440 | |||
2441 | ret = setup_out_fence(&f[(*num_fences)++], fence); | ||
2442 | if (ret) { | ||
2443 | dma_fence_put(fence); | ||
2444 | return ret; | ||
2445 | } | ||
2446 | |||
2447 | job->out_fence = fence; | ||
2448 | } | ||
2449 | |||
2369 | /* | 2450 | /* |
2370 | * Having this flag means user mode pends on event which will never | 2451 | * Having this flag means user mode pends on event which will never |
2371 | * reach due to lack of at least one CRTC for signaling | 2452 | * reach due to lack of at least one CRTC for signaling |
@@ -2376,11 +2457,11 @@ static int prepare_crtc_signaling(struct drm_device *dev, | |||
2376 | return 0; | 2457 | return 0; |
2377 | } | 2458 | } |
2378 | 2459 | ||
2379 | static void complete_crtc_signaling(struct drm_device *dev, | 2460 | static void complete_signaling(struct drm_device *dev, |
2380 | struct drm_atomic_state *state, | 2461 | struct drm_atomic_state *state, |
2381 | struct drm_out_fence_state *fence_state, | 2462 | struct drm_out_fence_state *fence_state, |
2382 | unsigned int num_fences, | 2463 | unsigned int num_fences, |
2383 | bool install_fds) | 2464 | bool install_fds) |
2384 | { | 2465 | { |
2385 | struct drm_crtc *crtc; | 2466 | struct drm_crtc *crtc; |
2386 | struct drm_crtc_state *crtc_state; | 2467 | struct drm_crtc_state *crtc_state; |
@@ -2550,8 +2631,8 @@ retry: | |||
2550 | drm_mode_object_put(obj); | 2631 | drm_mode_object_put(obj); |
2551 | } | 2632 | } |
2552 | 2633 | ||
2553 | ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state, | 2634 | ret = prepare_signaling(dev, state, arg, file_priv, &fence_state, |
2554 | &num_fences); | 2635 | &num_fences); |
2555 | if (ret) | 2636 | if (ret) |
2556 | goto out; | 2637 | goto out; |
2557 | 2638 | ||
@@ -2567,7 +2648,7 @@ retry: | |||
2567 | } | 2648 | } |
2568 | 2649 | ||
2569 | out: | 2650 | out: |
2570 | complete_crtc_signaling(dev, state, fence_state, num_fences, !ret); | 2651 | complete_signaling(dev, state, fence_state, num_fences, !ret); |
2571 | 2652 | ||
2572 | if (ret == -EDEADLK) { | 2653 | if (ret == -EDEADLK) { |
2573 | drm_atomic_state_clear(state); | 2654 | drm_atomic_state_clear(state); |
diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c index e5b8a4b79724..827395071f0b 100644 --- a/drivers/gpu/drm/drm_writeback.c +++ b/drivers/gpu/drm/drm_writeback.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <drm/drm_property.h> | 14 | #include <drm/drm_property.h> |
15 | #include <drm/drm_writeback.h> | 15 | #include <drm/drm_writeback.h> |
16 | #include <drm/drmP.h> | 16 | #include <drm/drmP.h> |
17 | #include <linux/dma-fence.h> | ||
17 | 18 | ||
18 | /** | 19 | /** |
19 | * DOC: overview | 20 | * DOC: overview |
@@ -31,6 +32,16 @@ | |||
31 | * framebuffer applies only to a single commit (see below). A framebuffer may | 32 | * framebuffer applies only to a single commit (see below). A framebuffer may |
32 | * not be attached while the CRTC is off. | 33 | * not be attached while the CRTC is off. |
33 | * | 34 | * |
35 | * Unlike with planes, when a writeback framebuffer is removed by userspace DRM | ||
36 | * makes no attempt to remove it from active use by the connector. This is | ||
37 | * because no method is provided to abort a writeback operation, and in any | ||
38 | * case making a new commit whilst a writeback is ongoing is undefined (see | ||
39 | * WRITEBACK_OUT_FENCE_PTR below). As soon as the current writeback is finished, | ||
40 | * the framebuffer will automatically no longer be in active use. As it will | ||
41 | * also have already been removed from the framebuffer list, there will be no | ||
42 | * way for any userspace application to retrieve a reference to it in the | ||
43 | * intervening period. | ||
44 | * | ||
34 | * Writeback connectors have some additional properties, which userspace | 45 | * Writeback connectors have some additional properties, which userspace |
35 | * can use to query and control them: | 46 | * can use to query and control them: |
36 | * | 47 | * |
@@ -47,8 +58,54 @@ | |||
47 | * data is an array of u32 DRM_FORMAT_* fourcc values. | 58 | * data is an array of u32 DRM_FORMAT_* fourcc values. |
48 | * Userspace can use this blob to find out what pixel formats are supported | 59 | * Userspace can use this blob to find out what pixel formats are supported |
49 | * by the connector's writeback engine. | 60 | * by the connector's writeback engine. |
61 | * | ||
62 | * "WRITEBACK_OUT_FENCE_PTR": | ||
63 | * Userspace can use this property to provide a pointer for the kernel to | ||
64 | * fill with a sync_file file descriptor, which will signal once the | ||
65 | * writeback is finished. The value should be the address of a 32-bit | ||
66 | * signed integer, cast to a u64. | ||
67 | * Userspace should wait for this fence to signal before making another | ||
68 | * commit affecting any of the same CRTCs, Planes or Connectors. | ||
69 | * **Failure to do so will result in undefined behaviour.** | ||
70 | * For this reason it is strongly recommended that all userspace | ||
71 | * applications making use of writeback connectors *always* retrieve an | ||
72 | * out-fence for the commit and use it appropriately. | ||
73 | * From userspace, this property will always read as zero. | ||
50 | */ | 74 | */ |
51 | 75 | ||
76 | #define fence_to_wb_connector(x) container_of(x->lock, \ | ||
77 | struct drm_writeback_connector, \ | ||
78 | fence_lock) | ||
79 | |||
80 | static const char *drm_writeback_fence_get_driver_name(struct dma_fence *fence) | ||
81 | { | ||
82 | struct drm_writeback_connector *wb_connector = | ||
83 | fence_to_wb_connector(fence); | ||
84 | |||
85 | return wb_connector->base.dev->driver->name; | ||
86 | } | ||
87 | |||
88 | static const char * | ||
89 | drm_writeback_fence_get_timeline_name(struct dma_fence *fence) | ||
90 | { | ||
91 | struct drm_writeback_connector *wb_connector = | ||
92 | fence_to_wb_connector(fence); | ||
93 | |||
94 | return wb_connector->timeline_name; | ||
95 | } | ||
96 | |||
97 | static bool drm_writeback_fence_enable_signaling(struct dma_fence *fence) | ||
98 | { | ||
99 | return true; | ||
100 | } | ||
101 | |||
102 | static const struct dma_fence_ops drm_writeback_fence_ops = { | ||
103 | .get_driver_name = drm_writeback_fence_get_driver_name, | ||
104 | .get_timeline_name = drm_writeback_fence_get_timeline_name, | ||
105 | .enable_signaling = drm_writeback_fence_enable_signaling, | ||
106 | .wait = dma_fence_default_wait, | ||
107 | }; | ||
108 | |||
52 | static int create_writeback_properties(struct drm_device *dev) | 109 | static int create_writeback_properties(struct drm_device *dev) |
53 | { | 110 | { |
54 | struct drm_property *prop; | 111 | struct drm_property *prop; |
@@ -72,6 +129,15 @@ static int create_writeback_properties(struct drm_device *dev) | |||
72 | dev->mode_config.writeback_pixel_formats_property = prop; | 129 | dev->mode_config.writeback_pixel_formats_property = prop; |
73 | } | 130 | } |
74 | 131 | ||
132 | if (!dev->mode_config.writeback_out_fence_ptr_property) { | ||
133 | prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, | ||
134 | "WRITEBACK_OUT_FENCE_PTR", 0, | ||
135 | U64_MAX); | ||
136 | if (!prop) | ||
137 | return -ENOMEM; | ||
138 | dev->mode_config.writeback_out_fence_ptr_property = prop; | ||
139 | } | ||
140 | |||
75 | return 0; | 141 | return 0; |
76 | } | 142 | } |
77 | 143 | ||
@@ -141,6 +207,15 @@ int drm_writeback_connector_init(struct drm_device *dev, | |||
141 | INIT_LIST_HEAD(&wb_connector->job_queue); | 207 | INIT_LIST_HEAD(&wb_connector->job_queue); |
142 | spin_lock_init(&wb_connector->job_lock); | 208 | spin_lock_init(&wb_connector->job_lock); |
143 | 209 | ||
210 | wb_connector->fence_context = dma_fence_context_alloc(1); | ||
211 | spin_lock_init(&wb_connector->fence_lock); | ||
212 | snprintf(wb_connector->timeline_name, | ||
213 | sizeof(wb_connector->timeline_name), | ||
214 | "CONNECTOR:%d-%s", connector->base.id, connector->name); | ||
215 | |||
216 | drm_object_attach_property(&connector->base, | ||
217 | config->writeback_out_fence_ptr_property, 0); | ||
218 | |||
144 | drm_object_attach_property(&connector->base, | 219 | drm_object_attach_property(&connector->base, |
145 | config->writeback_fb_id_property, 0); | 220 | config->writeback_fb_id_property, 0); |
146 | 221 | ||
@@ -210,6 +285,7 @@ static void cleanup_work(struct work_struct *work) | |||
210 | /** | 285 | /** |
211 | * drm_writeback_signal_completion - Signal the completion of a writeback job | 286 | * drm_writeback_signal_completion - Signal the completion of a writeback job |
212 | * @wb_connector: The writeback connector whose job is complete | 287 | * @wb_connector: The writeback connector whose job is complete |
288 | * @status: Status code to set in the writeback out_fence (0 for success) | ||
213 | * | 289 | * |
214 | * Drivers should call this to signal the completion of a previously queued | 290 | * Drivers should call this to signal the completion of a previously queued |
215 | * writeback job. It should be called as soon as possible after the hardware | 291 | * writeback job. It should be called as soon as possible after the hardware |
@@ -223,7 +299,8 @@ static void cleanup_work(struct work_struct *work) | |||
223 | * See also: drm_writeback_queue_job() | 299 | * See also: drm_writeback_queue_job() |
224 | */ | 300 | */ |
225 | void | 301 | void |
226 | drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) | 302 | drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector, |
303 | int status) | ||
227 | { | 304 | { |
228 | unsigned long flags; | 305 | unsigned long flags; |
229 | struct drm_writeback_job *job; | 306 | struct drm_writeback_job *job; |
@@ -232,8 +309,15 @@ drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) | |||
232 | job = list_first_entry_or_null(&wb_connector->job_queue, | 309 | job = list_first_entry_or_null(&wb_connector->job_queue, |
233 | struct drm_writeback_job, | 310 | struct drm_writeback_job, |
234 | list_entry); | 311 | list_entry); |
235 | if (job) | 312 | if (job) { |
236 | list_del(&job->list_entry); | 313 | list_del(&job->list_entry); |
314 | if (job->out_fence) { | ||
315 | if (status) | ||
316 | dma_fence_set_error(job->out_fence, status); | ||
317 | dma_fence_signal(job->out_fence); | ||
318 | dma_fence_put(job->out_fence); | ||
319 | } | ||
320 | } | ||
237 | spin_unlock_irqrestore(&wb_connector->job_lock, flags); | 321 | spin_unlock_irqrestore(&wb_connector->job_lock, flags); |
238 | 322 | ||
239 | if (WARN_ON(!job)) | 323 | if (WARN_ON(!job)) |
@@ -243,3 +327,24 @@ drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector) | |||
243 | queue_work(system_long_wq, &job->cleanup_work); | 327 | queue_work(system_long_wq, &job->cleanup_work); |
244 | } | 328 | } |
245 | EXPORT_SYMBOL(drm_writeback_signal_completion); | 329 | EXPORT_SYMBOL(drm_writeback_signal_completion); |
330 | |||
331 | struct dma_fence * | ||
332 | drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector) | ||
333 | { | ||
334 | struct dma_fence *fence; | ||
335 | |||
336 | if (WARN_ON(wb_connector->base.connector_type != | ||
337 | DRM_MODE_CONNECTOR_WRITEBACK)) | ||
338 | return NULL; | ||
339 | |||
340 | fence = kzalloc(sizeof(*fence), GFP_KERNEL); | ||
341 | if (!fence) | ||
342 | return NULL; | ||
343 | |||
344 | dma_fence_init(fence, &drm_writeback_fence_ops, | ||
345 | &wb_connector->fence_lock, wb_connector->fence_context, | ||
346 | ++wb_connector->fence_seqno); | ||
347 | |||
348 | return fence; | ||
349 | } | ||
350 | EXPORT_SYMBOL(drm_writeback_get_out_fence); | ||
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 8254521b4583..da9d95a19580 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h | |||
@@ -160,6 +160,14 @@ struct __drm_crtcs_state { | |||
160 | struct __drm_connnectors_state { | 160 | struct __drm_connnectors_state { |
161 | struct drm_connector *ptr; | 161 | struct drm_connector *ptr; |
162 | struct drm_connector_state *state, *old_state, *new_state; | 162 | struct drm_connector_state *state, *old_state, *new_state; |
163 | /** | ||
164 | * @out_fence_ptr: | ||
165 | * | ||
166 | * User-provided pointer which the kernel uses to return a sync_file | ||
167 | * file descriptor. Used by writeback connectors to signal completion of | ||
168 | * the writeback. | ||
169 | */ | ||
170 | s32 __user *out_fence_ptr; | ||
163 | }; | 171 | }; |
164 | 172 | ||
165 | struct drm_private_obj; | 173 | struct drm_private_obj; |
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 716c3a0e0e1d..14ab58ade87f 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h | |||
@@ -441,10 +441,10 @@ struct drm_connector_state { | |||
441 | /** | 441 | /** |
442 | * @writeback_job: Writeback job for writeback connectors | 442 | * @writeback_job: Writeback job for writeback connectors |
443 | * | 443 | * |
444 | * Holds the framebuffer for a writeback connector. As the writeback | 444 | * Holds the framebuffer and out-fence for a writeback connector. As |
445 | * completion may be asynchronous to the normal commit cycle, the | 445 | * the writeback completion may be asynchronous to the normal commit |
446 | * writeback job lifetime is managed separately from the normal atomic | 446 | * cycle, the writeback job lifetime is managed separately from the |
447 | * state by this object. | 447 | * normal atomic state by this object. |
448 | * | 448 | * |
449 | * See also: drm_writeback_queue_job() and | 449 | * See also: drm_writeback_queue_job() and |
450 | * drm_writeback_signal_completion() | 450 | * drm_writeback_signal_completion() |
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 5f24329e6927..f4a173c8d79c 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h | |||
@@ -798,6 +798,14 @@ struct drm_mode_config { | |||
798 | * See also: drm_writeback_connector_init() | 798 | * See also: drm_writeback_connector_init() |
799 | */ | 799 | */ |
800 | struct drm_property *writeback_pixel_formats_property; | 800 | struct drm_property *writeback_pixel_formats_property; |
801 | /** | ||
802 | * @writeback_out_fence_ptr_property: Property for writeback connectors, | ||
803 | * fd pointer representing the outgoing fences for a writeback | ||
804 | * connector. Userspace should provide a pointer to a value of type s32, | ||
805 | * and then cast that pointer to u64. | ||
806 | * See also: drm_writeback_connector_init() | ||
807 | */ | ||
808 | struct drm_property *writeback_out_fence_ptr_property; | ||
801 | 809 | ||
802 | /* dumb ioctl parameters */ | 810 | /* dumb ioctl parameters */ |
803 | uint32_t preferred_depth, prefer_shadow; | 811 | uint32_t preferred_depth, prefer_shadow; |
diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h index 17cd1feecd7e..a10fe556dfd4 100644 --- a/include/drm/drm_writeback.h +++ b/include/drm/drm_writeback.h | |||
@@ -50,6 +50,32 @@ struct drm_writeback_connector { | |||
50 | * drm_writeback_signal_completion() | 50 | * drm_writeback_signal_completion() |
51 | */ | 51 | */ |
52 | struct list_head job_queue; | 52 | struct list_head job_queue; |
53 | |||
54 | /** | ||
55 | * @fence_context: | ||
56 | * | ||
57 | * timeline context used for fence operations. | ||
58 | */ | ||
59 | unsigned int fence_context; | ||
60 | /** | ||
61 | * @fence_lock: | ||
62 | * | ||
63 | * spinlock to protect the fences in the fence_context. | ||
64 | */ | ||
65 | spinlock_t fence_lock; | ||
66 | /** | ||
67 | * @fence_seqno: | ||
68 | * | ||
69 | * Seqno variable used as monotonic counter for the fences | ||
70 | * created on the connector's timeline. | ||
71 | */ | ||
72 | unsigned long fence_seqno; | ||
73 | /** | ||
74 | * @timeline_name: | ||
75 | * | ||
76 | * The name of the connector's fence timeline. | ||
77 | */ | ||
78 | char timeline_name[32]; | ||
53 | }; | 79 | }; |
54 | 80 | ||
55 | struct drm_writeback_job { | 81 | struct drm_writeback_job { |
@@ -75,6 +101,13 @@ struct drm_writeback_job { | |||
75 | * directly, use drm_atomic_set_writeback_fb_for_connector() | 101 | * directly, use drm_atomic_set_writeback_fb_for_connector() |
76 | */ | 102 | */ |
77 | struct drm_framebuffer *fb; | 103 | struct drm_framebuffer *fb; |
104 | |||
105 | /** | ||
106 | * @out_fence: | ||
107 | * | ||
108 | * Fence which will signal once the writeback has completed | ||
109 | */ | ||
110 | struct dma_fence *out_fence; | ||
78 | }; | 111 | }; |
79 | 112 | ||
80 | int drm_writeback_connector_init(struct drm_device *dev, | 113 | int drm_writeback_connector_init(struct drm_device *dev, |
@@ -87,5 +120,11 @@ void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector, | |||
87 | struct drm_writeback_job *job); | 120 | struct drm_writeback_job *job); |
88 | 121 | ||
89 | void drm_writeback_cleanup_job(struct drm_writeback_job *job); | 122 | void drm_writeback_cleanup_job(struct drm_writeback_job *job); |
90 | void drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector); | 123 | |
124 | void | ||
125 | drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector, | ||
126 | int status); | ||
127 | |||
128 | struct dma_fence * | ||
129 | drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector); | ||
91 | #endif | 130 | #endif |