xref: /openbsd-src/sys/dev/pci/drm/i915/display/intel_global_state.c (revision de8cc8edbc71bd3e3bc7fbffa27ba0e564c37d8b)
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 	WARN(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 	int index, num_objs, i;
75 	size_t size;
76 	struct __intel_global_objs_state *arr;
77 	struct intel_global_state *obj_state;
78 
79 	for (i = 0; i < state->num_global_objs; i++)
80 		if (obj == state->global_objs[i].ptr)
81 			return state->global_objs[i].state;
82 
83 	assert_global_state_read_locked(state);
84 
85 	num_objs = state->num_global_objs + 1;
86 	size = sizeof(*state->global_objs) * num_objs;
87 #ifdef __linux__
88 	arr = krealloc(state->global_objs, size, GFP_KERNEL);
89 	if (!arr)
90 		return ERR_PTR(-ENOMEM);
91 #else
92 	arr = kmalloc(size, GFP_KERNEL);
93 	if (!arr)
94 		return ERR_PTR(-ENOMEM);
95 	memcpy(arr, state->global_objs,
96 	    sizeof(*state->global_objs) * state->num_global_objs);
97 	kfree(state->global_objs);
98 #endif
99 
100 	state->global_objs = arr;
101 	index = state->num_global_objs;
102 	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
103 
104 	obj_state = obj->funcs->atomic_duplicate_state(obj);
105 	if (!obj_state)
106 		return ERR_PTR(-ENOMEM);
107 
108 	obj_state->changed = false;
109 
110 	state->global_objs[index].state = obj_state;
111 	state->global_objs[index].old_state = obj->state;
112 	state->global_objs[index].new_state = obj_state;
113 	state->global_objs[index].ptr = obj;
114 	obj_state->state = state;
115 
116 	state->num_global_objs = num_objs;
117 
118 	DRM_DEBUG_ATOMIC("Added new global object %p state %p to %p\n",
119 			 obj, obj_state, state);
120 
121 	return obj_state;
122 }
123 
124 struct intel_global_state *
125 intel_atomic_get_old_global_obj_state(struct intel_atomic_state *state,
126 				      struct intel_global_obj *obj)
127 {
128 	int i;
129 
130 	for (i = 0; i < state->num_global_objs; i++)
131 		if (obj == state->global_objs[i].ptr)
132 			return state->global_objs[i].old_state;
133 
134 	return NULL;
135 }
136 
137 struct intel_global_state *
138 intel_atomic_get_new_global_obj_state(struct intel_atomic_state *state,
139 				      struct intel_global_obj *obj)
140 {
141 	int i;
142 
143 	for (i = 0; i < state->num_global_objs; i++)
144 		if (obj == state->global_objs[i].ptr)
145 			return state->global_objs[i].new_state;
146 
147 	return NULL;
148 }
149 
150 void intel_atomic_swap_global_state(struct intel_atomic_state *state)
151 {
152 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
153 	struct intel_global_state *old_obj_state, *new_obj_state;
154 	struct intel_global_obj *obj;
155 	int i;
156 
157 	for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
158 					    new_obj_state, i) {
159 		WARN_ON(obj->state != old_obj_state);
160 
161 		/*
162 		 * If the new state wasn't modified (and properly
163 		 * locked for write access) we throw it away.
164 		 */
165 		if (!new_obj_state->changed)
166 			continue;
167 
168 		assert_global_state_write_locked(dev_priv);
169 
170 		old_obj_state->state = state;
171 		new_obj_state->state = NULL;
172 
173 		state->global_objs[i].state = old_obj_state;
174 		obj->state = new_obj_state;
175 	}
176 }
177 
178 void intel_atomic_clear_global_state(struct intel_atomic_state *state)
179 {
180 	int i;
181 
182 	for (i = 0; i < state->num_global_objs; i++) {
183 		struct intel_global_obj *obj = state->global_objs[i].ptr;
184 
185 		obj->funcs->atomic_destroy_state(obj,
186 						 state->global_objs[i].state);
187 		state->global_objs[i].ptr = NULL;
188 		state->global_objs[i].state = NULL;
189 		state->global_objs[i].old_state = NULL;
190 		state->global_objs[i].new_state = NULL;
191 	}
192 	state->num_global_objs = 0;
193 }
194 
195 int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
196 {
197 	struct intel_atomic_state *state = obj_state->state;
198 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
199 	struct intel_crtc *crtc;
200 
201 	for_each_intel_crtc(&dev_priv->drm, crtc) {
202 		int ret;
203 
204 		ret = drm_modeset_lock(&crtc->base.mutex,
205 				       state->base.acquire_ctx);
206 		if (ret)
207 			return ret;
208 	}
209 
210 	obj_state->changed = true;
211 
212 	return 0;
213 }
214 
215 int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
216 {
217 	struct intel_atomic_state *state = obj_state->state;
218 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
219 	struct intel_crtc *crtc;
220 
221 	for_each_intel_crtc(&dev_priv->drm, crtc) {
222 		struct intel_crtc_state *crtc_state;
223 
224 		crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
225 		if (IS_ERR(crtc_state))
226 			return PTR_ERR(crtc_state);
227 	}
228 
229 	obj_state->changed = true;
230 
231 	return 0;
232 }
233