]> Git Repo - linux.git/blob - drivers/gpu/drm/i915/display/intel_global_state.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / i915 / display / intel_global_state.c
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
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
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
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
48 static void commit_put(struct intel_global_commit *commit)
49 {
50         if (commit)
51                 kref_put(&commit->ref, __commit_free);
52 }
53
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
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 *
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
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)
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, &display->global.obj_list);
92 }
93
94 void intel_atomic_global_obj_cleanup(struct intel_display *display)
95 {
96         struct intel_global_obj *obj, *next;
97
98         list_for_each_entry_safe(obj, next, &display->global.obj_list, head) {
99                 list_del(&obj->head);
100
101                 drm_WARN_ON(display->drm, kref_read(&obj->state->ref) != 1);
102                 intel_atomic_global_state_put(obj->state);
103         }
104 }
105
106 static void assert_global_state_write_locked(struct intel_display *display)
107 {
108         struct intel_crtc *crtc;
109
110         for_each_intel_crtc(display->drm, crtc)
111                 drm_modeset_lock_assert_held(&crtc->base.mutex);
112 }
113
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
127 static void assert_global_state_read_locked(struct intel_atomic_state *state)
128 {
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;
132
133         for_each_intel_crtc(display->drm, crtc) {
134                 if (modeset_lock_is_held(ctx, &crtc->base.mutex))
135                         return;
136         }
137
138         drm_WARN(display->drm, 1, "Global state not read locked\n");
139 }
140
141 struct intel_global_state *
142 intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
143                                   struct intel_global_obj *obj)
144 {
145         struct intel_display *display = to_intel_display(state);
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         arr = krealloc(state->global_objs, size, GFP_KERNEL);
160         if (!arr)
161                 return ERR_PTR(-ENOMEM);
162
163         state->global_objs = arr;
164         index = state->num_global_objs;
165         memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
166
167         obj_state = obj->funcs->atomic_duplicate_state(obj);
168         if (!obj_state)
169                 return ERR_PTR(-ENOMEM);
170
171         obj_state->obj = obj;
172         obj_state->changed = false;
173         obj_state->serialized = false;
174         obj_state->commit = NULL;
175
176         kref_init(&obj_state->ref);
177
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;
184
185         state->num_global_objs = num_objs;
186
187         drm_dbg_atomic(display->drm, "Added new global object %p state %p to %p\n",
188                        obj, obj_state, state);
189
190         return obj_state;
191 }
192
193 struct intel_global_state *
194 intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
195                                       struct intel_global_obj *obj)
196 {
197         int i;
198
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;
202
203         return NULL;
204 }
205
206 struct intel_global_state *
207 intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
208                                       struct intel_global_obj *obj)
209 {
210         int i;
211
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;
215
216         return NULL;
217 }
218
219 void intel_atomic_swap_global_state(struct intel_atomic_state *state)
220 {
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;
224         int i;
225
226         for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
227                                             new_obj_state, i) {
228                 drm_WARN_ON(display->drm, obj->state != old_obj_state);
229
230                 /*
231                  * If the new state wasn't modified (and properly
232                  * locked for write access) we throw it away.
233                  */
234                 if (!new_obj_state->changed)
235                         continue;
236
237                 assert_global_state_write_locked(display);
238
239                 old_obj_state->state = state;
240                 new_obj_state->state = NULL;
241
242                 state->global_objs[i].state = old_obj_state;
243
244                 intel_atomic_global_state_put(obj->state);
245                 obj->state = intel_atomic_global_state_get(new_obj_state);
246         }
247 }
248
249 void intel_atomic_clear_global_state(struct intel_atomic_state *state)
250 {
251         int i;
252
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);
256
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;
261         }
262         state->num_global_objs = 0;
263 }
264
265 int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
266 {
267         struct intel_atomic_state *state = obj_state->state;
268         struct intel_display *display = to_intel_display(state);
269         struct intel_crtc *crtc;
270
271         for_each_intel_crtc(display->drm, crtc) {
272                 int ret;
273
274                 ret = drm_modeset_lock(&crtc->base.mutex,
275                                        state->base.acquire_ctx);
276                 if (ret)
277                         return ret;
278         }
279
280         obj_state->changed = true;
281
282         return 0;
283 }
284
285 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
286 {
287         int ret;
288
289         ret = intel_atomic_lock_global_state(obj_state);
290         if (ret)
291                 return ret;
292
293         obj_state->serialized = true;
294
295         return 0;
296 }
297
298 bool
299 intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
300 {
301         struct intel_display *display = to_intel_display(state);
302         struct intel_crtc *crtc;
303
304         for_each_intel_crtc(display->drm, crtc)
305                 if (!intel_atomic_get_new_crtc_state(state, crtc))
306                         return false;
307         return true;
308 }
309
310 int
311 intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
312 {
313         const struct intel_global_state *old_obj_state;
314         struct intel_global_state *new_obj_state;
315         struct intel_global_obj *obj;
316         int i;
317
318         for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
319                                             new_obj_state, i) {
320                 struct intel_global_commit *commit = NULL;
321
322                 if (new_obj_state->serialized) {
323                         /*
324                          * New commit which is going to be completed
325                          * after the hardware reprogramming is done.
326                          */
327                         commit = commit_new();
328                         if (!commit)
329                                 return -ENOMEM;
330                 } else if (new_obj_state->changed) {
331                         /*
332                          * We're going to swap to this state, so carry the
333                          * previous commit along, in case it's not yet done.
334                          */
335                         commit = commit_get(old_obj_state->commit);
336                 }
337
338                 new_obj_state->commit = commit;
339         }
340
341         return 0;
342 }
343
344 int
345 intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
346 {
347         struct intel_display *display = to_intel_display(state);
348         const struct intel_global_state *old_obj_state;
349         struct intel_global_obj *obj;
350         int i;
351
352         for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
353                 struct intel_global_commit *commit = old_obj_state->commit;
354                 long ret;
355
356                 if (!commit)
357                         continue;
358
359                 ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
360                 if (ret == 0) {
361                         drm_err(display->drm, "global state timed out\n");
362                         return -ETIMEDOUT;
363                 }
364         }
365
366         return 0;
367 }
368
369 void
370 intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
371 {
372         const struct intel_global_state *new_obj_state;
373         struct intel_global_obj *obj;
374         int i;
375
376         for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
377                 struct intel_global_commit *commit = new_obj_state->commit;
378
379                 if (!new_obj_state->serialized)
380                         continue;
381
382                 complete_all(&commit->done);
383         }
384 }
This page took 0.058039 seconds and 4 git commands to generate.