Loading...
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
13struct intel_global_commit {
14 struct kref ref;
15 struct completion done;
16};
17
18static 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
32static 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
40static 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
48static void commit_put(struct intel_global_commit *commit)
49{
50 if (commit)
51 kref_put(&commit->ref, __commit_free);
52}
53
54static 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
65static 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
70static struct intel_global_state *
71intel_atomic_global_state_get(struct intel_global_state *obj_state)
72{
73 kref_get(&obj_state->ref);
74
75 return obj_state;
76}
77
78void 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
94void 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
106static 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
114static 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
127static 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
141struct intel_global_state *
142intel_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 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(&i915->drm, "Added new global object %p state %p to %p\n",
188 obj, obj_state, state);
189
190 return obj_state;
191}
192
193struct intel_global_state *
194intel_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
206struct intel_global_state *
207intel_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
219void intel_atomic_swap_global_state(struct intel_atomic_state *state)
220{
221 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
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(&dev_priv->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(dev_priv);
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
249void 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
265int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
266{
267 struct intel_atomic_state *state = obj_state->state;
268 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
269 struct intel_crtc *crtc;
270
271 for_each_intel_crtc(&dev_priv->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
285int 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
298bool
299intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
300{
301 struct drm_i915_private *i915 = to_i915(state->base.dev);
302 struct intel_crtc *crtc;
303
304 for_each_intel_crtc(&i915->drm, crtc)
305 if (!intel_atomic_get_new_crtc_state(state, crtc))
306 return false;
307 return true;
308}
309
310int
311intel_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
344int
345intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
346{
347 struct drm_i915_private *i915 = to_i915(state->base.dev);
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(&i915->drm, "global state timed out\n");
362 return -ETIMEDOUT;
363 }
364 }
365
366 return 0;
367}
368
369void
370intel_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}
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
13static void __intel_atomic_global_state_free(struct kref *kref)
14{
15 struct intel_global_state *obj_state =
16 container_of(kref, struct intel_global_state, ref);
17 struct intel_global_obj *obj = obj_state->obj;
18
19 obj->funcs->atomic_destroy_state(obj, obj_state);
20}
21
22static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
23{
24 kref_put(&obj_state->ref, __intel_atomic_global_state_free);
25}
26
27static struct intel_global_state *
28intel_atomic_global_state_get(struct intel_global_state *obj_state)
29{
30 kref_get(&obj_state->ref);
31
32 return obj_state;
33}
34
35void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv,
36 struct intel_global_obj *obj,
37 struct intel_global_state *state,
38 const struct intel_global_state_funcs *funcs)
39{
40 memset(obj, 0, sizeof(*obj));
41
42 state->obj = obj;
43
44 kref_init(&state->ref);
45
46 obj->state = state;
47 obj->funcs = funcs;
48 list_add_tail(&obj->head, &dev_priv->global_obj_list);
49}
50
51void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv)
52{
53 struct intel_global_obj *obj, *next;
54
55 list_for_each_entry_safe(obj, next, &dev_priv->global_obj_list, head) {
56 list_del(&obj->head);
57
58 drm_WARN_ON(&dev_priv->drm, kref_read(&obj->state->ref) != 1);
59 intel_atomic_global_state_put(obj->state);
60 }
61}
62
63static void assert_global_state_write_locked(struct drm_i915_private *dev_priv)
64{
65 struct intel_crtc *crtc;
66
67 for_each_intel_crtc(&dev_priv->drm, crtc)
68 drm_modeset_lock_assert_held(&crtc->base.mutex);
69}
70
71static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx,
72 struct drm_modeset_lock *lock)
73{
74 struct drm_modeset_lock *l;
75
76 list_for_each_entry(l, &ctx->locked, head) {
77 if (lock == l)
78 return true;
79 }
80
81 return false;
82}
83
84static void assert_global_state_read_locked(struct intel_atomic_state *state)
85{
86 struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx;
87 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
88 struct intel_crtc *crtc;
89
90 for_each_intel_crtc(&dev_priv->drm, crtc) {
91 if (modeset_lock_is_held(ctx, &crtc->base.mutex))
92 return;
93 }
94
95 drm_WARN(&dev_priv->drm, 1, "Global state not read locked\n");
96}
97
98struct intel_global_state *
99intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
100 struct intel_global_obj *obj)
101{
102 struct drm_i915_private *i915 = to_i915(state->base.dev);
103 int index, num_objs, i;
104 size_t size;
105 struct __intel_global_objs_state *arr;
106 struct intel_global_state *obj_state;
107
108 for (i = 0; i < state->num_global_objs; i++)
109 if (obj == state->global_objs[i].ptr)
110 return state->global_objs[i].state;
111
112 assert_global_state_read_locked(state);
113
114 num_objs = state->num_global_objs + 1;
115 size = sizeof(*state->global_objs) * num_objs;
116 arr = krealloc(state->global_objs, size, GFP_KERNEL);
117 if (!arr)
118 return ERR_PTR(-ENOMEM);
119
120 state->global_objs = arr;
121 index = state->num_global_objs;
122 memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
123
124 obj_state = obj->funcs->atomic_duplicate_state(obj);
125 if (!obj_state)
126 return ERR_PTR(-ENOMEM);
127
128 obj_state->obj = obj;
129 obj_state->changed = false;
130
131 kref_init(&obj_state->ref);
132
133 state->global_objs[index].state = obj_state;
134 state->global_objs[index].old_state =
135 intel_atomic_global_state_get(obj->state);
136 state->global_objs[index].new_state = obj_state;
137 state->global_objs[index].ptr = obj;
138 obj_state->state = state;
139
140 state->num_global_objs = num_objs;
141
142 drm_dbg_atomic(&i915->drm, "Added new global object %p state %p to %p\n",
143 obj, obj_state, state);
144
145 return obj_state;
146}
147
148struct intel_global_state *
149intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
150 struct intel_global_obj *obj)
151{
152 int i;
153
154 for (i = 0; i < state->num_global_objs; i++)
155 if (obj == state->global_objs[i].ptr)
156 return state->global_objs[i].old_state;
157
158 return NULL;
159}
160
161struct intel_global_state *
162intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
163 struct intel_global_obj *obj)
164{
165 int i;
166
167 for (i = 0; i < state->num_global_objs; i++)
168 if (obj == state->global_objs[i].ptr)
169 return state->global_objs[i].new_state;
170
171 return NULL;
172}
173
174void intel_atomic_swap_global_state(struct intel_atomic_state *state)
175{
176 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
177 struct intel_global_state *old_obj_state, *new_obj_state;
178 struct intel_global_obj *obj;
179 int i;
180
181 for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
182 new_obj_state, i) {
183 drm_WARN_ON(&dev_priv->drm, obj->state != old_obj_state);
184
185 /*
186 * If the new state wasn't modified (and properly
187 * locked for write access) we throw it away.
188 */
189 if (!new_obj_state->changed)
190 continue;
191
192 assert_global_state_write_locked(dev_priv);
193
194 old_obj_state->state = state;
195 new_obj_state->state = NULL;
196
197 state->global_objs[i].state = old_obj_state;
198
199 intel_atomic_global_state_put(obj->state);
200 obj->state = intel_atomic_global_state_get(new_obj_state);
201 }
202}
203
204void intel_atomic_clear_global_state(struct intel_atomic_state *state)
205{
206 int i;
207
208 for (i = 0; i < state->num_global_objs; i++) {
209 intel_atomic_global_state_put(state->global_objs[i].old_state);
210 intel_atomic_global_state_put(state->global_objs[i].new_state);
211
212 state->global_objs[i].ptr = NULL;
213 state->global_objs[i].state = NULL;
214 state->global_objs[i].old_state = NULL;
215 state->global_objs[i].new_state = NULL;
216 }
217 state->num_global_objs = 0;
218}
219
220int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
221{
222 struct intel_atomic_state *state = obj_state->state;
223 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
224 struct intel_crtc *crtc;
225
226 for_each_intel_crtc(&dev_priv->drm, crtc) {
227 int ret;
228
229 ret = drm_modeset_lock(&crtc->base.mutex,
230 state->base.acquire_ctx);
231 if (ret)
232 return ret;
233 }
234
235 obj_state->changed = true;
236
237 return 0;
238}
239
240int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
241{
242 struct intel_atomic_state *state = obj_state->state;
243 struct drm_i915_private *dev_priv = to_i915(state->base.dev);
244 struct intel_crtc *crtc;
245
246 for_each_intel_crtc(&dev_priv->drm, crtc) {
247 struct intel_crtc_state *crtc_state;
248
249 crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
250 if (IS_ERR(crtc_state))
251 return PTR_ERR(crtc_state);
252 }
253
254 obj_state->changed = true;
255
256 return 0;
257}