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}
385