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