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 void intel_atomic_global_obj_init(struct drm_i915_private *dev_priv,
14 				  struct intel_global_obj *obj,
15 				  struct intel_global_state *state,
16 				  const struct intel_global_state_funcs *funcs)
17 {
18 	memset(obj, 0, sizeof(*obj));
19 
20 	obj->state = state;
21 	obj->funcs = funcs;
22 	list_add_tail(&obj->head, &dev_priv->global_obj_list);
23 }
24 
25 void intel_atomic_global_obj_cleanup(struct drm_i915_private *dev_priv)
26 {
27 	struct intel_global_obj *obj, *next;
28 
29 	list_for_each_entry_safe(obj, next, &dev_priv->global_obj_list, head) {
30 		list_del(&obj->head);
31 		obj->funcs->atomic_destroy_state(obj, obj->state);
32 	}
33 }
34 
35 static void assert_global_state_write_locked(struct drm_i915_private *dev_priv)
36 {
37 	struct intel_crtc *crtc;
38 
39 	for_each_intel_crtc(&dev_priv->drm, crtc)
40 		drm_modeset_lock_assert_held(&crtc->base.mutex);
41 }
42 
43 static bool modeset_lock_is_held(struct drm_modeset_acquire_ctx *ctx,
44 				 struct drm_modeset_lock *lock)
45 {
46 	struct drm_modeset_lock *l;
47 
48 	list_for_each_entry(l, &ctx->locked, head) {
49 		if (lock == l)
50 			return true;
51 	}
52 
53 	return false;
54 }
55 
56 static void assert_global_state_read_locked(struct intel_atomic_state *state)
57 {
58 	struct drm_modeset_acquire_ctx *ctx = state->base.acquire_ctx;
59 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
60 	struct intel_crtc *crtc;
61 
62 	for_each_intel_crtc(&dev_priv->drm, crtc) {
63 		if (modeset_lock_is_held(ctx, &crtc->base.mutex))
64 			return;
65 	}
66 
67 	drm_WARN(&dev_priv->drm, 1, "Global state not read locked\n");
68 }
69 
70 struct intel_global_state *
71 intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
72 				  struct intel_global_obj *obj)
73 {
74 	struct drm_i915_private *i915 = to_i915(state->base.dev);
75 	int index, num_objs, i;
76 	size_t size;
77 	struct __intel_global_objs_state *arr;
78 	struct intel_global_state *obj_state;
79 
80 	for (i = 0; i < state->num_global_objs; i++)
81 		if (obj == state->global_objs[i].ptr)
82 			return state->global_objs[i].state;
83 
84 	assert_global_state_read_locked(state);
85 
86 	num_objs = state->num_global_objs + 1;
87 	size = sizeof(*state->global_objs) * num_objs;
88 	arr = krealloc(state->global_objs, size, GFP_KERNEL);
89 	if (!arr)
90 		return ERR_PTR(-ENOMEM);
91 
92 	state->global_objs = arr;
93 	index = state->num_global_objs;
94 	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
95 
96 	obj_state = obj->funcs->atomic_duplicate_state(obj);
97 	if (!obj_state)
98 		return ERR_PTR(-ENOMEM);
99 
100 	obj_state->changed = false;
101 
102 	state->global_objs[index].state = obj_state;
103 	state->global_objs[index].old_state = obj->state;
104 	state->global_objs[index].new_state = obj_state;
105 	state->global_objs[index].ptr = obj;
106 	obj_state->state = state;
107 
108 	state->num_global_objs = num_objs;
109 
110 	drm_dbg_atomic(&i915->drm, "Added new global object %p state %p to %p\n",
111 		       obj, obj_state, state);
112 
113 	return obj_state;
114 }
115 
116 struct intel_global_state *
117 intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
118 				      struct intel_global_obj *obj)
119 {
120 	int i;
121 
122 	for (i = 0; i < state->num_global_objs; i++)
123 		if (obj == state->global_objs[i].ptr)
124 			return state->global_objs[i].old_state;
125 
126 	return NULL;
127 }
128 
129 struct intel_global_state *
130 intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
131 				      struct intel_global_obj *obj)
132 {
133 	int i;
134 
135 	for (i = 0; i < state->num_global_objs; i++)
136 		if (obj == state->global_objs[i].ptr)
137 			return state->global_objs[i].new_state;
138 
139 	return NULL;
140 }
141 
142 void intel_atomic_swap_global_state(struct intel_atomic_state *state)
143 {
144 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
145 	struct intel_global_state *old_obj_state, *new_obj_state;
146 	struct intel_global_obj *obj;
147 	int i;
148 
149 	for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
150 					    new_obj_state, i) {
151 		drm_WARN_ON(&dev_priv->drm, obj->state != old_obj_state);
152 
153 		/*
154 		 * If the new state wasn't modified (and properly
155 		 * locked for write access) we throw it away.
156 		 */
157 		if (!new_obj_state->changed)
158 			continue;
159 
160 		assert_global_state_write_locked(dev_priv);
161 
162 		old_obj_state->state = state;
163 		new_obj_state->state = NULL;
164 
165 		state->global_objs[i].state = old_obj_state;
166 		obj->state = new_obj_state;
167 	}
168 }
169 
170 void intel_atomic_clear_global_state(struct intel_atomic_state *state)
171 {
172 	int i;
173 
174 	for (i = 0; i < state->num_global_objs; i++) {
175 		struct intel_global_obj *obj = state->global_objs[i].ptr;
176 
177 		obj->funcs->atomic_destroy_state(obj,
178 						 state->global_objs[i].state);
179 		state->global_objs[i].ptr = NULL;
180 		state->global_objs[i].state = NULL;
181 		state->global_objs[i].old_state = NULL;
182 		state->global_objs[i].new_state = NULL;
183 	}
184 	state->num_global_objs = 0;
185 }
186 
187 int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
188 {
189 	struct intel_atomic_state *state = obj_state->state;
190 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
191 	struct intel_crtc *crtc;
192 
193 	for_each_intel_crtc(&dev_priv->drm, crtc) {
194 		int ret;
195 
196 		ret = drm_modeset_lock(&crtc->base.mutex,
197 				       state->base.acquire_ctx);
198 		if (ret)
199 			return ret;
200 	}
201 
202 	obj_state->changed = true;
203 
204 	return 0;
205 }
206 
207 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
208 {
209 	struct intel_atomic_state *state = obj_state->state;
210 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
211 	struct intel_crtc *crtc;
212 
213 	for_each_intel_crtc(&dev_priv->drm, crtc) {
214 		struct intel_crtc_state *crtc_state;
215 
216 		crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
217 		if (IS_ERR(crtc_state))
218 			return PTR_ERR(crtc_state);
219 	}
220 
221 	obj_state->changed = true;
222 
223 	return 0;
224 }
225