xref: /linux/drivers/gpu/drm/i915/i915_fb_pin.c (revision b226489de47c0eba740ef8c4857aecb06e482952)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2021 Intel Corporation
4  */
5 
6 #include <drm/drm_print.h>
7 #include <drm/intel/display_parent_interface.h>
8 
9 #include "gem/i915_gem_domain.h"
10 #include "gem/i915_gem_object.h"
11 
12 #include "i915_fb_pin.h"
13 #include "i915_dpt.h"
14 #include "i915_drv.h"
15 #include "i915_vma.h"
16 
17 static struct i915_vma *
18 intel_fb_pin_to_dpt(struct drm_gem_object *_obj, struct intel_dpt *dpt,
19 		    const struct intel_fb_pin_params *pin_params)
20 {
21 	struct drm_i915_private *i915 = to_i915(_obj->dev);
22 	struct drm_i915_gem_object *obj = to_intel_bo(_obj);
23 	struct i915_address_space *vm = i915_dpt_to_vm(dpt);
24 	struct i915_gem_ww_ctx ww;
25 	struct i915_vma *vma;
26 	int ret;
27 
28 	/*
29 	 * We are not syncing against the binding (and potential migrations)
30 	 * below, so this vm must never be async.
31 	 */
32 	if (drm_WARN_ON(&i915->drm, vm->bind_async_flags))
33 		return ERR_PTR(-EINVAL);
34 
35 	if (WARN_ON(!i915_gem_object_is_framebuffer(obj)))
36 		return ERR_PTR(-EINVAL);
37 
38 	atomic_inc(&i915->pending_fb_pin);
39 
40 	for_i915_gem_ww(&ww, ret, true) {
41 		ret = i915_gem_object_lock(obj, &ww);
42 		if (ret)
43 			continue;
44 
45 		if (HAS_LMEM(i915)) {
46 			unsigned int flags = obj->flags;
47 
48 			/*
49 			 * For this type of buffer we need to able to read from the CPU
50 			 * the clear color value found in the buffer, hence we need to
51 			 * ensure it is always in the mappable part of lmem, if this is
52 			 * a small-bar device.
53 			 */
54 			if (pin_params->needs_cpu_lmem_access)
55 				flags &= ~I915_BO_ALLOC_GPU_ONLY;
56 			ret = __i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0,
57 							flags);
58 			if (ret)
59 				continue;
60 		}
61 
62 		ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE);
63 		if (ret)
64 			continue;
65 
66 		vma = i915_vma_instance(obj, vm, pin_params->view);
67 		if (IS_ERR(vma)) {
68 			ret = PTR_ERR(vma);
69 			continue;
70 		}
71 
72 		if (i915_vma_misplaced(vma, 0, pin_params->alignment, 0)) {
73 			ret = i915_vma_unbind(vma);
74 			if (ret)
75 				continue;
76 		}
77 
78 		ret = i915_vma_pin_ww(vma, &ww, 0, pin_params->alignment,
79 				      PIN_GLOBAL);
80 		if (ret)
81 			continue;
82 	}
83 	if (ret) {
84 		vma = ERR_PTR(ret);
85 		goto err;
86 	}
87 
88 	vma->display_alignment = max(vma->display_alignment,
89 				     pin_params->alignment);
90 
91 	i915_gem_object_flush_if_display(obj);
92 
93 	i915_vma_get(vma);
94 
95 	/*
96 	 * The DPT object contains only one vma, and there is no VT-d
97 	 * guard, so the VMA's offset within the DPT is always 0.
98 	 */
99 	drm_WARN_ON(&i915->drm, i915_dpt_offset(vma));
100 err:
101 	atomic_dec(&i915->pending_fb_pin);
102 
103 	return vma;
104 }
105 
106 static struct i915_vma *
107 intel_fb_pin_to_ggtt(struct drm_gem_object *_obj,
108 		     const struct intel_fb_pin_params *pin_params,
109 		     int *out_fence_id)
110 {
111 	struct drm_i915_private *i915 = to_i915(_obj->dev);
112 	struct drm_i915_gem_object *obj = to_intel_bo(_obj);
113 	intel_wakeref_t wakeref;
114 	struct i915_gem_ww_ctx ww;
115 	struct i915_vma *vma;
116 	unsigned int pinctl;
117 	int ret;
118 
119 	if (drm_WARN_ON(&i915->drm, !i915_gem_object_is_framebuffer(obj)))
120 		return ERR_PTR(-EINVAL);
121 
122 	if (drm_WARN_ON(&i915->drm, pin_params->alignment &&
123 			!is_power_of_2(pin_params->alignment)))
124 		return ERR_PTR(-EINVAL);
125 
126 	/*
127 	 * Global gtt pte registers are special registers which actually forward
128 	 * writes to a chunk of system memory. Which means that there is no risk
129 	 * that the register values disappear as soon as we call
130 	 * intel_runtime_pm_put(), so it is correct to wrap only the
131 	 * pin/unpin/fence and not more.
132 	 */
133 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
134 
135 	atomic_inc(&i915->pending_fb_pin);
136 
137 	pinctl = 0;
138 	/* PIN_MAPPABLE limits the address to GMADR size */
139 	if (pin_params->needs_low_address)
140 		pinctl |= PIN_MAPPABLE;
141 
142 	i915_gem_ww_ctx_init(&ww, true);
143 retry:
144 	ret = i915_gem_object_lock(obj, &ww);
145 	if (!ret && pin_params->needs_physical)
146 		ret = i915_gem_object_attach_phys(obj, pin_params->phys_alignment);
147 	else if (!ret && HAS_LMEM(i915))
148 		ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0);
149 	if (!ret)
150 		ret = i915_gem_object_pin_pages(obj);
151 	if (ret)
152 		goto err;
153 
154 	vma = i915_gem_object_pin_to_display_plane(obj, &ww,
155 						   pin_params->alignment,
156 						   pin_params->vtd_guard,
157 						   pin_params->view, pinctl);
158 	if (IS_ERR(vma)) {
159 		ret = PTR_ERR(vma);
160 		goto err_unpin;
161 	}
162 
163 	if (out_fence_id)
164 		*out_fence_id = -1;
165 
166 	if (out_fence_id && i915_vma_is_map_and_fenceable(vma)) {
167 		/*
168 		 * Install a fence for tiled scan-out. Pre-i965 always needs a
169 		 * fence, whereas 965+ only requires a fence if using
170 		 * framebuffer compression.  For simplicity, we always, when
171 		 * possible, install a fence as the cost is not that onerous.
172 		 *
173 		 * If we fail to fence the tiled scanout, then either the
174 		 * modeset will reject the change (which is highly unlikely as
175 		 * the affected systems, all but one, do not have unmappable
176 		 * space) or we will not be able to enable full powersaving
177 		 * techniques (also likely not to apply due to various limits
178 		 * FBC and the like impose on the size of the buffer, which
179 		 * presumably we violated anyway with this unmappable buffer).
180 		 * Anyway, it is presumably better to stumble onwards with
181 		 * something and try to run the system in a "less than optimal"
182 		 * mode that matches the user configuration.
183 		 */
184 		ret = i915_vma_pin_fence(vma);
185 		if (ret != 0 && pin_params->needs_fence) {
186 			i915_vma_unpin(vma);
187 			goto err_unpin;
188 		}
189 		ret = 0;
190 
191 		if (vma->fence)
192 			*out_fence_id = vma->fence->id;
193 	}
194 
195 	i915_vma_get(vma);
196 
197 err_unpin:
198 	i915_gem_object_unpin_pages(obj);
199 err:
200 	if (ret == -EDEADLK) {
201 		ret = i915_gem_ww_ctx_backoff(&ww);
202 		if (!ret)
203 			goto retry;
204 	}
205 	i915_gem_ww_ctx_fini(&ww);
206 	if (ret)
207 		vma = ERR_PTR(ret);
208 
209 	atomic_dec(&i915->pending_fb_pin);
210 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
211 	return vma;
212 }
213 
214 static void intel_fb_unpin_vma(struct i915_vma *vma, int fence_id)
215 {
216 	if (fence_id >= 0)
217 		i915_vma_unpin_fence(vma);
218 	i915_vma_unpin(vma);
219 	i915_vma_put(vma);
220 }
221 
222 static int i915_fb_pin_ggtt_pin(struct drm_gem_object *obj,
223 				const struct intel_fb_pin_params *pin_params,
224 				struct i915_vma **out_ggtt_vma,
225 				u32 *out_offset,
226 				int *out_fence_id)
227 {
228 	struct i915_vma *ggtt_vma;
229 
230 	ggtt_vma = intel_fb_pin_to_ggtt(obj, pin_params, out_fence_id);
231 	if (IS_ERR(ggtt_vma))
232 		return PTR_ERR(ggtt_vma);
233 
234 	*out_ggtt_vma = ggtt_vma;
235 
236 	/*
237 	 * Pre-populate the dma address before we enter the vblank
238 	 * evade critical section as i915_gem_object_get_dma_address()
239 	 * will trigger might_sleep() even if it won't actually sleep,
240 	 * which is the case when the fb has already been pinned.
241 	 */
242 	if (pin_params->needs_physical)
243 		*out_offset = i915_gem_object_get_dma_address(to_intel_bo(obj), 0);
244 	else
245 		*out_offset = i915_ggtt_offset(ggtt_vma);
246 
247 	return 0;
248 }
249 
250 static void i915_fb_pin_ggtt_unpin(struct i915_vma *ggtt_vma,
251 				   int fence_id)
252 {
253 	if (ggtt_vma)
254 		intel_fb_unpin_vma(ggtt_vma, fence_id);
255 }
256 
257 static int i915_fb_pin_dpt_pin(struct drm_gem_object *obj, struct intel_dpt *dpt,
258 			       const struct intel_fb_pin_params *pin_params,
259 			       struct i915_vma **out_dpt_vma,
260 			       struct i915_vma **out_ggtt_vma,
261 			       u32 *out_offset)
262 {
263 	struct i915_vma *ggtt_vma, *dpt_vma;
264 
265 	WARN_ON(!dpt);
266 
267 	ggtt_vma = i915_dpt_pin_to_ggtt(dpt, pin_params->alignment / 512);
268 	if (IS_ERR(ggtt_vma))
269 		return PTR_ERR(ggtt_vma);
270 
271 	dpt_vma = intel_fb_pin_to_dpt(obj, dpt, pin_params);
272 	if (IS_ERR(dpt_vma)) {
273 		i915_dpt_unpin_from_ggtt(dpt);
274 		return PTR_ERR(dpt_vma);
275 	}
276 
277 	drm_WARN_ON(obj->dev, ggtt_vma == dpt_vma);
278 
279 	*out_ggtt_vma = ggtt_vma;
280 	*out_dpt_vma = dpt_vma;
281 
282 	*out_offset = i915_ggtt_offset(ggtt_vma);
283 
284 	return 0;
285 }
286 
287 static void i915_fb_pin_dpt_unpin(struct intel_dpt *dpt,
288 				  struct i915_vma *dpt_vma,
289 				  struct i915_vma *ggtt_vma)
290 {
291 	WARN_ON(!dpt);
292 	WARN_ON(!!dpt_vma != !!ggtt_vma);
293 
294 	if (dpt_vma)
295 		intel_fb_unpin_vma(dpt_vma, -1);
296 	if (ggtt_vma)
297 		i915_dpt_unpin_from_ggtt(dpt);
298 }
299 
300 static void i915_fb_pin_get_map(struct i915_vma *vma, struct iosys_map *map)
301 {
302 	iosys_map_set_vaddr_iomem(map, i915_vma_get_iomap(vma));
303 }
304 
305 const struct intel_display_fb_pin_interface i915_display_fb_pin_interface = {
306 	.ggtt_pin = i915_fb_pin_ggtt_pin,
307 	.ggtt_unpin = i915_fb_pin_ggtt_unpin,
308 	.dpt_pin = i915_fb_pin_dpt_pin,
309 	.dpt_unpin = i915_fb_pin_dpt_unpin,
310 	.get_map = i915_fb_pin_get_map,
311 };
312