Add the 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
Signed-off-by: Brian Starkey
---
drivers/gpu/drm/drm_atomic.c| 96 +
drivers/gpu/drm/drm_writeback.c | 99 ++-
include/drm/drm_atomic.h|8
include/drm/drm_connector.h |8 ++--
include/drm/drm_writeback.h | 39 ++-
5 files changed, 234 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 343e2b7..0e3c900 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -308,6 +308,32 @@ static s64 __user *get_out_fence_for_crtc(struct
drm_atomic_state *state,
return fence_ptr;
}
+static int set_out_fence_for_connector(struct drm_atomic_state *state,
+ struct drm_connector *connector,
+ s64 __user *fence_ptr)
+{
+ unsigned int index = drm_connector_index(connector);
+
+ if (fence_ptr && put_user(-1, fence_ptr))
+ return -EFAULT;
+
+ state->connectors[index].out_fence_ptr = fence_ptr;
+
+ return 0;
+}
+
+static s64 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
+ struct drm_connector *connector)
+{
+ unsigned int index = drm_connector_index(connector);
+ s64 __user *fence_ptr;
+
+ fence_ptr = state->connectors[index].out_fence_ptr;
+ state->connectors[index].out_fence_ptr = NULL;
+
+ return fence_ptr;
+}
+
/**
* drm_atomic_set_mode_for_crtc - set mode for CRTC
* @state: the CRTC whose incoming state to update
@@ -696,6 +722,12 @@ static int drm_atomic_connector_check(struct drm_connector
*connector,
return -EINVAL;
}
+ if (writeback_job->out_fence && !writeback_job->fb) {
+ DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] requesting out-fence
without framebuffer\n",
+connector->base.id, connector->name);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -1134,6 +1166,11 @@ int drm_atomic_connector_set_property(struct
drm_connector *connector,
if (fb)
drm_framebuffer_unreference(fb);
return ret;
+ } else if (property == config->prop_out_fence_ptr) {
+ s64 __user *fence_ptr = u64_to_user_ptr(val);
+
+ return set_out_fence_for_connector(state->state, connector,
+ fence_ptr);
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
@@ -1185,6 +1222,8 @@ static void drm_atomic_connector_print_state(struct
drm_printer *p,
} else if (property == config->writeback_fb_id_property) {
/* Writeback framebuffer is one-shot, write and forget */
*val = 0;
+ } else if (property == config->prop_out_fence_ptr) {
+ *val = 0;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
@@ -1976,7 +2015,7 @@ static int setup_out_fence(struct drm_out_fence_state
*fence_state,
return 0;
}
-static int prepare_crtc_signaling(struct drm_device *dev,
+static int prepare_signaling(struct drm_device *dev,
struct drm_atomic_state *state,
struct drm_mode_atomic *arg,
struct drm_file *file_priv,
@@ -1985,6 +2024,8 @@ static int prepare_crtc_signaling(struct drm_device *dev,
{
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
int i, ret;
if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
@@ -2048,14 +2089,51 @@ static int prepare_crtc_signaling(struct drm_device
*dev,
}
}
+ for_each_connector_in_state(state, conn, conn_state, i) {
+ struct drm_writeback_job