summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_global_state.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2023-12-19 15:07:55 +0200
committerVille Syrjälä <ville.syrjala@linux.intel.com>2024-02-02 23:02:58 +0200
commite0aee99015a79cf57b653668b06bccc9964b0387 (patch)
treeca00f700df918380d7053d70eac52eb767799fc0 /drivers/gpu/drm/i915/display/intel_global_state.c
parent1e41fa9452039beea297105fb6f7f68cb2774e1a (diff)
drm/i915: Rework global state serializaiton
Instead of injecting extra crtc commits to serialize the global state let's hand roll a bit of commit machinery to take care of the hardware synchronization. Rather than basing everything on the crtc commits we track these as their own thing. I think this makes more sense as the hardware blocks we are working with are not in any way tied to the pipes, so the completion should not be tied in with the vblank machinery either. The difference to the old behaviour is that: - we no longer pull extra crtcs into the commit which should make drm_atomic_check_only() happier - since those crtcs don't get pulled in we also don't end up reprogamming them and thus don't need to wait their vblanks to pass/etc. So this should be tad faster as well. TODO: perhaps have each global object complete its own commit once the post-plane update phase is done? Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6728 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20231219130756.25986-3-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_global_state.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_global_state.c137
1 files changed, 126 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
index e8e8be54143b..cbcd1e91b7be 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.c
+++ b/drivers/gpu/drm/i915/display/intel_global_state.c
@@ -10,12 +10,55 @@
#include "intel_display_types.h"
#include "intel_global_state.h"
+struct intel_global_commit {
+ struct kref ref;
+ struct completion done;
+};
+
+static struct intel_global_commit *commit_new(void)
+{
+ struct intel_global_commit *commit;
+
+ commit = kzalloc(sizeof(*commit), GFP_KERNEL);
+ if (!commit)
+ return NULL;
+
+ init_completion(&commit->done);
+ kref_init(&commit->ref);
+
+ return commit;
+}
+
+static void __commit_free(struct kref *kref)
+{
+ struct intel_global_commit *commit =
+ container_of(kref, typeof(*commit), ref);
+
+ kfree(commit);
+}
+
+static struct intel_global_commit *commit_get(struct intel_global_commit *commit)
+{
+ if (commit)
+ kref_get(&commit->ref);
+
+ return commit;
+}
+
+static void commit_put(struct intel_global_commit *commit)
+{
+ if (commit)
+ kref_put(&commit->ref, __commit_free);
+}
+
static void __intel_atomic_global_state_free(struct kref *kref)
{
struct intel_global_state *obj_state =
container_of(kref, struct intel_global_state, ref);
struct intel_global_obj *obj = obj_state->obj;
+ commit_put(obj_state->commit);
+
obj->funcs->atomic_destroy_state(obj, obj_state);
}
@@ -127,6 +170,8 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
obj_state->obj = obj;
obj_state->changed = false;
+ obj_state->serialized = false;
+ obj_state->commit = NULL;
kref_init(&obj_state->ref);
@@ -239,19 +284,13 @@ int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
{
- struct intel_atomic_state *state = obj_state->state;
- struct drm_i915_private *dev_priv = to_i915(state->base.dev);
- struct intel_crtc *crtc;
+ int ret;
- for_each_intel_crtc(&dev_priv->drm, crtc) {
- struct intel_crtc_state *crtc_state;
+ ret = intel_atomic_lock_global_state(obj_state);
+ if (ret)
+ return ret;
- crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
- }
-
- obj_state->changed = true;
+ obj_state->serialized = true;
return 0;
}
@@ -267,3 +306,79 @@ intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
return false;
return true;
}
+
+int
+intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
+{
+ const struct intel_global_state *old_obj_state;
+ struct intel_global_state *new_obj_state;
+ struct intel_global_obj *obj;
+ int i;
+
+ for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
+ new_obj_state, i) {
+ struct intel_global_commit *commit = NULL;
+
+ if (new_obj_state->serialized) {
+ /*
+ * New commit which is going to be completed
+ * after the hardware reprogramming is done.
+ */
+ commit = commit_new();
+ if (!commit)
+ return -ENOMEM;
+ } else if (new_obj_state->changed) {
+ /*
+ * We're going to swap to this state, so carry the
+ * previous commit along, in case it's not yet done.
+ */
+ commit = commit_get(old_obj_state->commit);
+ }
+
+ new_obj_state->commit = commit;
+ }
+
+ return 0;
+}
+
+int
+intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
+{
+ struct drm_i915_private *i915 = to_i915(state->base.dev);
+ const struct intel_global_state *old_obj_state;
+ struct intel_global_obj *obj;
+ int i;
+
+ for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
+ struct intel_global_commit *commit = old_obj_state->commit;
+ long ret;
+
+ if (!commit)
+ continue;
+
+ ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
+ if (ret == 0) {
+ drm_err(&i915->drm, "global state timed out\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+void
+intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
+{
+ const struct intel_global_state *new_obj_state;
+ struct intel_global_obj *obj;
+ int i;
+
+ for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
+ struct intel_global_commit *commit = new_obj_state->commit;
+
+ if (!new_obj_state->serialized)
+ continue;
+
+ complete_all(&commit->done);
+ }
+}