1 // SPDX-License-Identifier: MIT
3 * Copyright © 2020 Intel Corporation
6 #include <linux/string.h>
9 #include "intel_atomic.h"
10 #include "intel_display_types.h"
11 #include "intel_global_state.h"
13 struct intel_global_commit {
15 struct completion done;
18 static struct intel_global_commit *commit_new(void)
20 struct intel_global_commit *commit;
22 commit = kzalloc(sizeof(*commit), GFP_KERNEL);
26 init_completion(&commit->done);
27 kref_init(&commit->ref);
32 static void __commit_free(struct kref *kref)
34 struct intel_global_commit *commit =
35 container_of(kref, typeof(*commit), ref);
40 static struct intel_global_commit *commit_get(struct intel_global_commit *commit)
43 kref_get(&commit->ref);
48 static void commit_put(struct intel_global_commit *commit)
51 kref_put(&commit->ref, __commit_free);
54 static void __intel_atomic_global_state_free(struct kref *kref)
56 struct intel_global_state *obj_state =
57 container_of(kref, struct intel_global_state, ref);
58 struct intel_global_obj *obj = obj_state->obj;
60 commit_put(obj_state->commit);
62 obj->funcs->atomic_destroy_state(obj, obj_state);
65 static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
67 kref_put(&obj_state->ref, __intel_atomic_global_state_free);
70 static struct intel_global_state *
71 intel_atomic_global_state_get(struct intel_global_state *obj_state)
73 kref_get(&obj_state->ref);
78 void intel_atomic_global_obj_init(struct intel_display *display,
79 struct intel_global_obj *obj,
80 struct intel_global_state *state,
81 const struct intel_global_state_funcs *funcs)
83 memset(obj, 0, sizeof(*obj));
87 kref_init(&state->ref);
91 list_add_tail(&obj->head, &display->global.obj_list);
94 void intel_atomic_global_obj_cleanup(struct intel_display *display)
96 struct intel_global_obj *obj, *next;
98 list_for_each_entry_safe(obj, next, &display->global.obj_list, head) {
101 drm_WARN_ON(display->drm, kref_read(&obj->state->ref) != 1);
102 intel_atomic_global_state_put(obj->state);
106 static void assert_global_state_write_locked(struct intel_display *display)
108 struct intel_crtc *crtc;
110 for_each_intel_crtc(display->drm, crtc)
111 drm_modeset_lock_assert_held(&crtc->base.mutex);
114 static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx,
115 struct drm_modeset_lock *lock)
117 struct drm_modeset_lock *l;
119 list_for_each_entry(l, &ctx->locked, head) {
127 static void assert_global_state_read_locked(struct intel_atomic_state *state)
129 struct intel_display *display = to_intel_display(state);
130 struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx;
131 struct intel_crtc *crtc;
133 for_each_intel_crtc(display->drm, crtc) {
134 if (modeset_lock_is_held(ctx, &crtc->base.mutex))
138 drm_WARN(display->drm, 1, "Global state not read locked\n");
141 struct intel_global_state *
142 intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
143 struct intel_global_obj *obj)
145 struct intel_display *display = to_intel_display(state);
146 int index, num_objs, i;
148 struct __intel_global_objs_state *arr;
149 struct intel_global_state *obj_state;
151 for (i = 0; i < state->num_global_objs; i++)
152 if (obj == state->global_objs[i].ptr)
153 return state->global_objs[i].state;
155 assert_global_state_read_locked(state);
157 num_objs = state->num_global_objs + 1;
158 size = sizeof(*state->global_objs) * num_objs;
159 arr = krealloc(state->global_objs, size, GFP_KERNEL);
161 return ERR_PTR(-ENOMEM);
163 state->global_objs = arr;
164 index = state->num_global_objs;
165 memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
167 obj_state = obj->funcs->atomic_duplicate_state(obj);
169 return ERR_PTR(-ENOMEM);
171 obj_state->obj = obj;
172 obj_state->changed = false;
173 obj_state->serialized = false;
174 obj_state->commit = NULL;
176 kref_init(&obj_state->ref);
178 state->global_objs[index].state = obj_state;
179 state->global_objs[index].old_state =
180 intel_atomic_global_state_get(obj->state);
181 state->global_objs[index].new_state = obj_state;
182 state->global_objs[index].ptr = obj;
183 obj_state->state = state;
185 state->num_global_objs = num_objs;
187 drm_dbg_atomic(display->drm, "Added new global object %p state %p to %p\n",
188 obj, obj_state, state);
193 struct intel_global_state *
194 intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
195 struct intel_global_obj *obj)
199 for (i = 0; i < state->num_global_objs; i++)
200 if (obj == state->global_objs[i].ptr)
201 return state->global_objs[i].old_state;
206 struct intel_global_state *
207 intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
208 struct intel_global_obj *obj)
212 for (i = 0; i < state->num_global_objs; i++)
213 if (obj == state->global_objs[i].ptr)
214 return state->global_objs[i].new_state;
219 void intel_atomic_swap_global_state(struct intel_atomic_state *state)
221 struct intel_display *display = to_intel_display(state);
222 struct intel_global_state *old_obj_state, *new_obj_state;
223 struct intel_global_obj *obj;
226 for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
228 drm_WARN_ON(display->drm, obj->state != old_obj_state);
231 * If the new state wasn't modified (and properly
232 * locked for write access) we throw it away.
234 if (!new_obj_state->changed)
237 assert_global_state_write_locked(display);
239 old_obj_state->state = state;
240 new_obj_state->state = NULL;
242 state->global_objs[i].state = old_obj_state;
244 intel_atomic_global_state_put(obj->state);
245 obj->state = intel_atomic_global_state_get(new_obj_state);
249 void intel_atomic_clear_global_state(struct intel_atomic_state *state)
253 for (i = 0; i < state->num_global_objs; i++) {
254 intel_atomic_global_state_put(state->global_objs[i].old_state);
255 intel_atomic_global_state_put(state->global_objs[i].new_state);
257 state->global_objs[i].ptr = NULL;
258 state->global_objs[i].state = NULL;
259 state->global_objs[i].old_state = NULL;
260 state->global_objs[i].new_state = NULL;
262 state->num_global_objs = 0;
265 int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
267 struct intel_atomic_state *state = obj_state->state;
268 struct intel_display *display = to_intel_display(state);
269 struct intel_crtc *crtc;
271 for_each_intel_crtc(display->drm, crtc) {
274 ret = drm_modeset_lock(&crtc->base.mutex,
275 state->base.acquire_ctx);
280 obj_state->changed = true;
285 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
289 ret = intel_atomic_lock_global_state(obj_state);
293 obj_state->serialized = true;
299 intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
301 struct intel_display *display = to_intel_display(state);
302 struct intel_crtc *crtc;
304 for_each_intel_crtc(display->drm, crtc)
305 if (!intel_atomic_get_new_crtc_state(state, crtc))
311 intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
313 const struct intel_global_state *old_obj_state;
314 struct intel_global_state *new_obj_state;
315 struct intel_global_obj *obj;
318 for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
320 struct intel_global_commit *commit = NULL;
322 if (new_obj_state->serialized) {
324 * New commit which is going to be completed
325 * after the hardware reprogramming is done.
327 commit = commit_new();
330 } else if (new_obj_state->changed) {
332 * We're going to swap to this state, so carry the
333 * previous commit along, in case it's not yet done.
335 commit = commit_get(old_obj_state->commit);
338 new_obj_state->commit = commit;
345 intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
347 struct intel_display *display = to_intel_display(state);
348 const struct intel_global_state *old_obj_state;
349 struct intel_global_obj *obj;
352 for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
353 struct intel_global_commit *commit = old_obj_state->commit;
359 ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
361 drm_err(display->drm, "global state timed out\n");
370 intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
372 const struct intel_global_state *new_obj_state;
373 struct intel_global_obj *obj;
376 for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
377 struct intel_global_commit *commit = new_obj_state->commit;
379 if (!new_obj_state->serialized)
382 complete_all(&commit->done);