1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2020 Intel Corporation
4 */
5
6 #include <linux/string.h>
7
8 #include "i915_drv.h"
9 #include "intel_atomic.h"
10 #include "intel_display_types.h"
11 #include "intel_global_state.h"
12
13 struct intel_global_commit {
14 struct kref ref;
15 struct completion done;
16 };
17
commit_new(void)18 static struct intel_global_commit *commit_new(void)
19 {
20 struct intel_global_commit *commit;
21
22 commit = kzalloc(sizeof(*commit), GFP_KERNEL);
23 if (!commit)
24 return NULL;
25
26 init_completion(&commit->done);
27 kref_init(&commit->ref);
28
29 return commit;
30 }
31
__commit_free(struct kref * kref)32 static void __commit_free(struct kref *kref)
33 {
34 struct intel_global_commit *commit =
35 container_of(kref, typeof(*commit), ref);
36
37 kfree(commit);
38 }
39
commit_get(struct intel_global_commit * commit)40 static struct intel_global_commit *commit_get(struct intel_global_commit *commit)
41 {
42 if (commit)
43 kref_get(&commit->ref);
44
45 return commit;
46 }
47
commit_put(struct intel_global_commit * commit)48 static void commit_put(struct intel_global_commit *commit)
49 {
50 if (commit)
51 kref_put(&commit->ref, __commit_free);
52 }
53
__intel_atomic_global_state_free(struct kref * kref)54 static void __intel_atomic_global_state_free(struct kref *kref)
55 {
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;
59
60 commit_put(obj_state->commit);
61
62 obj->funcs->atomic_destroy_state(obj, obj_state);
63 }
64
intel_atomic_global_state_put(struct intel_global_state * obj_state)65 static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
66 {
67 kref_put(&obj_state->ref, __intel_atomic_global_state_free);
68 }
69
70 static struct intel_global_state *
intel_atomic_global_state_get(struct intel_global_state * obj_state)71 intel_atomic_global_state_get(struct intel_global_state *obj_state)
72 {
73 kref_get(&obj_state->ref);
74
75 return obj_state;
76 }
77
intel_atomic_global_obj_init(struct drm_i915_private * dev_priv,struct intel_global_obj * obj,struct intel_global_state * state,const struct intel_global_state_funcs * funcs)78 void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv,
79 struct intel_global_obj *obj,
80 struct intel_global_state *state,
81 const struct intel_global_state_funcs *funcs)
82 {
83 memset(obj, 0, sizeof(*obj));
84
85 state->obj = obj;
86
87 kref_init(&state->ref);
88
89 obj->state = state;
90 obj->funcs = funcs;
91 list_add_tail(&obj->head, &dev_priv->display.global.obj_list);
92 }
93
intel_atomic_global_obj_cleanup(struct drm_i915_private * dev_priv)94 void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv)
95 {
96 struct intel_global_obj *obj, *next;
97
98 list_for_each_entry_safe(obj, next, &dev_priv->display.global.obj_list, head) {
99 list_del(&obj->head);
100
101 drm_WARN_ON(&dev_priv->drm, kref_read(&obj->state->ref) != 1);
102 intel_atomic_global_state_put(obj->state);
103 }
104 }
105
assert_global_state_write_locked(struct drm_i915_private * dev_priv)106 static void assert_global_state_write_locked(struct drm_i915_private *dev_priv)
107 {
108 struct intel_crtc *crtc;
109
110 for_each_intel_crtc(&dev_priv->drm, crtc)
111 drm_modeset_lock_assert_held(&crtc->base.mutex);
112 }
113
modeset_lock_is_held(struct drm_modeset_acquire_ctx * ctx,struct drm_modeset_lock * lock)114 static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx,
115 struct drm_modeset_lock *lock)
116 {
117 struct drm_modeset_lock *l;
118
119 list_for_each_entry(l, &ctx->locked, head) {
120 if (lock == l)
121 return true;
122 }
123
124 return false;
125 }
126
assert_global_state_read_locked(struct intel_atomic_state * state)127 static void assert_global_state_read_locked(struct intel_atomic_state *state)
128 {
129 struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx;
130 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
131 struct intel_crtc *crtc;
132
133 for_each_intel_crtc(&dev_priv->drm, crtc) {
134 if (modeset_lock_is_held(ctx, &crtc->base.mutex))
135 return;
136 }
137
138 drm_WARN(&dev_priv->drm, 1, "Global state not read locked\n");
139 }
140
141 struct intel_global_state *
intel_atomic_get_global_obj_state(struct intel_atomic_state * state,struct intel_global_obj * obj)142 intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
143 struct intel_global_obj *obj)
144 {
145 struct drm_i915_private *i915 = to_i915(state->base.dev);
146 int index, num_objs, i;
147 size_t size;
148 struct __intel_global_objs_state *arr;
149 struct intel_global_state *obj_state;
150
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;
154
155 assert_global_state_read_locked(state);
156
157 num_objs = state->num_global_objs + 1;
158 size = sizeof(*state->global_objs) * num_objs;
159 #ifdef __linux__
160 arr = krealloc(state->global_objs, size, GFP_KERNEL);
161 if (!arr)
162 return ERR_PTR(-ENOMEM);
163 #else
164 arr = kmalloc(size, GFP_KERNEL);
165 if (!arr)
166 return ERR_PTR(-ENOMEM);
167 memcpy(arr, state->global_objs,
168 sizeof(*state->global_objs) * state->num_global_objs);
169 kfree(state->global_objs);
170 #endif
171
172 state->global_objs = arr;
173 index = state->num_global_objs;
174 memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
175
176 obj_state = obj->funcs->atomic_duplicate_state(obj);
177 if (!obj_state)
178 return ERR_PTR(-ENOMEM);
179
180 obj_state->obj = obj;
181 obj_state->changed = false;
182 obj_state->serialized = false;
183 obj_state->commit = NULL;
184
185 kref_init(&obj_state->ref);
186
187 state->global_objs[index].state = obj_state;
188 state->global_objs[index].old_state =
189 intel_atomic_global_state_get(obj->state);
190 state->global_objs[index].new_state = obj_state;
191 state->global_objs[index].ptr = obj;
192 obj_state->state = state;
193
194 state->num_global_objs = num_objs;
195
196 drm_dbg_atomic(&i915->drm, "Added new global object %p state %p to %p\n",
197 obj, obj_state, state);
198
199 return obj_state;
200 }
201
202 struct intel_global_state *
intel_atomic_get_old_global_obj_state(struct intel_atomic_state * state,struct intel_global_obj * obj)203 intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
204 struct intel_global_obj *obj)
205 {
206 int i;
207
208 for (i = 0; i < state->num_global_objs; i++)
209 if (obj == state->global_objs[i].ptr)
210 return state->global_objs[i].old_state;
211
212 return NULL;
213 }
214
215 struct intel_global_state *
intel_atomic_get_new_global_obj_state(struct intel_atomic_state * state,struct intel_global_obj * obj)216 intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
217 struct intel_global_obj *obj)
218 {
219 int i;
220
221 for (i = 0; i < state->num_global_objs; i++)
222 if (obj == state->global_objs[i].ptr)
223 return state->global_objs[i].new_state;
224
225 return NULL;
226 }
227
intel_atomic_swap_global_state(struct intel_atomic_state * state)228 void intel_atomic_swap_global_state(struct intel_atomic_state *state)
229 {
230 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
231 struct intel_global_state *old_obj_state, *new_obj_state;
232 struct intel_global_obj *obj;
233 int i;
234
235 for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
236 new_obj_state, i) {
237 drm_WARN_ON(&dev_priv->drm, obj->state != old_obj_state);
238
239 /*
240 * If the new state wasn't modified (and properly
241 * locked for write access) we throw it away.
242 */
243 if (!new_obj_state->changed)
244 continue;
245
246 assert_global_state_write_locked(dev_priv);
247
248 old_obj_state->state = state;
249 new_obj_state->state = NULL;
250
251 state->global_objs[i].state = old_obj_state;
252
253 intel_atomic_global_state_put(obj->state);
254 obj->state = intel_atomic_global_state_get(new_obj_state);
255 }
256 }
257
intel_atomic_clear_global_state(struct intel_atomic_state * state)258 void intel_atomic_clear_global_state(struct intel_atomic_state *state)
259 {
260 int i;
261
262 for (i = 0; i < state->num_global_objs; i++) {
263 intel_atomic_global_state_put(state->global_objs[i].old_state);
264 intel_atomic_global_state_put(state->global_objs[i].new_state);
265
266 state->global_objs[i].ptr = NULL;
267 state->global_objs[i].state = NULL;
268 state->global_objs[i].old_state = NULL;
269 state->global_objs[i].new_state = NULL;
270 }
271 state->num_global_objs = 0;
272 }
273
intel_atomic_lock_global_state(struct intel_global_state * obj_state)274 int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
275 {
276 struct intel_atomic_state *state = obj_state->state;
277 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
278 struct intel_crtc *crtc;
279
280 for_each_intel_crtc(&dev_priv->drm, crtc) {
281 int ret;
282
283 ret = drm_modeset_lock(&crtc->base.mutex,
284 state->base.acquire_ctx);
285 if (ret)
286 return ret;
287 }
288
289 obj_state->changed = true;
290
291 return 0;
292 }
293
intel_atomic_serialize_global_state(struct intel_global_state * obj_state)294 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
295 {
296 int ret;
297
298 ret = intel_atomic_lock_global_state(obj_state);
299 if (ret)
300 return ret;
301
302 obj_state->serialized = true;
303
304 return 0;
305 }
306
307 bool
intel_atomic_global_state_is_serialized(struct intel_atomic_state * state)308 intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
309 {
310 struct drm_i915_private *i915 = to_i915(state->base.dev);
311 struct intel_crtc *crtc;
312
313 for_each_intel_crtc(&i915->drm, crtc)
314 if (!intel_atomic_get_new_crtc_state(state, crtc))
315 return false;
316 return true;
317 }
318
319 int
intel_atomic_global_state_setup_commit(struct intel_atomic_state * state)320 intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
321 {
322 const struct intel_global_state *old_obj_state;
323 struct intel_global_state *new_obj_state;
324 struct intel_global_obj *obj;
325 int i;
326
327 for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
328 new_obj_state, i) {
329 struct intel_global_commit *commit = NULL;
330
331 if (new_obj_state->serialized) {
332 /*
333 * New commit which is going to be completed
334 * after the hardware reprogramming is done.
335 */
336 commit = commit_new();
337 if (!commit)
338 return -ENOMEM;
339 } else if (new_obj_state->changed) {
340 /*
341 * We're going to swap to this state, so carry the
342 * previous commit along, in case it's not yet done.
343 */
344 commit = commit_get(old_obj_state->commit);
345 }
346
347 new_obj_state->commit = commit;
348 }
349
350 return 0;
351 }
352
353 int
intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state * state)354 intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
355 {
356 struct drm_i915_private *i915 = to_i915(state->base.dev);
357 const struct intel_global_state *old_obj_state;
358 struct intel_global_obj *obj;
359 int i;
360
361 for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
362 struct intel_global_commit *commit = old_obj_state->commit;
363 long ret;
364
365 if (!commit)
366 continue;
367
368 ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
369 if (ret == 0) {
370 drm_err(&i915->drm, "global state timed out\n");
371 return -ETIMEDOUT;
372 }
373 }
374
375 return 0;
376 }
377
378 void
intel_atomic_global_state_commit_done(struct intel_atomic_state * state)379 intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
380 {
381 const struct intel_global_state *new_obj_state;
382 struct intel_global_obj *obj;
383 int i;
384
385 for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
386 struct intel_global_commit *commit = new_obj_state->commit;
387
388 if (!new_obj_state->serialized)
389 continue;
390
391 complete_all(&commit->done);
392 }
393 }
394