xref: /linux/drivers/gpu/drm/i915/i915_fb_pin.c (revision b226489de47c0eba740ef8c4857aecb06e482952)
17d718850SJani Nikula // SPDX-License-Identifier: MIT
27d718850SJani Nikula /*
37d718850SJani Nikula  * Copyright © 2021 Intel Corporation
47d718850SJani Nikula  */
57d718850SJani Nikula 
67d718850SJani Nikula #include <drm/drm_print.h>
7c2b4b607SVille Syrjälä #include <drm/intel/display_parent_interface.h>
87d718850SJani Nikula 
97d718850SJani Nikula #include "gem/i915_gem_domain.h"
107d718850SJani Nikula #include "gem/i915_gem_object.h"
117d718850SJani Nikula 
12c2b4b607SVille Syrjälä #include "i915_fb_pin.h"
137d718850SJani Nikula #include "i915_dpt.h"
147d718850SJani Nikula #include "i915_drv.h"
157d718850SJani Nikula #include "i915_vma.h"
167d718850SJani Nikula 
177d718850SJani Nikula static struct i915_vma *
184fe8f832SVille Syrjälä intel_fb_pin_to_dpt(struct drm_gem_object *_obj, struct intel_dpt *dpt,
19a89b7f72SVille Syrjälä 		    const struct intel_fb_pin_params *pin_params)
207d718850SJani Nikula {
214fe8f832SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(_obj->dev);
227d718850SJani Nikula 	struct drm_i915_gem_object *obj = to_intel_bo(_obj);
237d718850SJani Nikula 	struct i915_address_space *vm = i915_dpt_to_vm(dpt);
247d718850SJani Nikula 	struct i915_gem_ww_ctx ww;
257d718850SJani Nikula 	struct i915_vma *vma;
267d718850SJani Nikula 	int ret;
277d718850SJani Nikula 
287d718850SJani Nikula 	/*
297d718850SJani Nikula 	 * We are not syncing against the binding (and potential migrations)
307d718850SJani Nikula 	 * below, so this vm must never be async.
317d718850SJani Nikula 	 */
323823bf01SJani Nikula 	if (drm_WARN_ON(&i915->drm, vm->bind_async_flags))
337d718850SJani Nikula 		return ERR_PTR(-EINVAL);
347d718850SJani Nikula 
357d718850SJani Nikula 	if (WARN_ON(!i915_gem_object_is_framebuffer(obj)))
367d718850SJani Nikula 		return ERR_PTR(-EINVAL);
377d718850SJani Nikula 
386dc69ca3SVille Syrjälä 	atomic_inc(&i915->pending_fb_pin);
397d718850SJani Nikula 
407d718850SJani Nikula 	for_i915_gem_ww(&ww, ret, true) {
417d718850SJani Nikula 		ret = i915_gem_object_lock(obj, &ww);
427d718850SJani Nikula 		if (ret)
437d718850SJani Nikula 			continue;
447d718850SJani Nikula 
453823bf01SJani Nikula 		if (HAS_LMEM(i915)) {
467d718850SJani Nikula 			unsigned int flags = obj->flags;
477d718850SJani Nikula 
487d718850SJani Nikula 			/*
497d718850SJani Nikula 			 * For this type of buffer we need to able to read from the CPU
507d718850SJani Nikula 			 * the clear color value found in the buffer, hence we need to
517d718850SJani Nikula 			 * ensure it is always in the mappable part of lmem, if this is
527d718850SJani Nikula 			 * a small-bar device.
537d718850SJani Nikula 			 */
542423bd7eSVille Syrjälä 			if (pin_params->needs_cpu_lmem_access)
557d718850SJani Nikula 				flags &= ~I915_BO_ALLOC_GPU_ONLY;
567d718850SJani Nikula 			ret = __i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0,
577d718850SJani Nikula 							flags);
587d718850SJani Nikula 			if (ret)
597d718850SJani Nikula 				continue;
607d718850SJani Nikula 		}
617d718850SJani Nikula 
627d718850SJani Nikula 		ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE);
637d718850SJani Nikula 		if (ret)
647d718850SJani Nikula 			continue;
657d718850SJani Nikula 
66a89b7f72SVille Syrjälä 		vma = i915_vma_instance(obj, vm, pin_params->view);
677d718850SJani Nikula 		if (IS_ERR(vma)) {
687d718850SJani Nikula 			ret = PTR_ERR(vma);
697d718850SJani Nikula 			continue;
707d718850SJani Nikula 		}
717d718850SJani Nikula 
72a89b7f72SVille Syrjälä 		if (i915_vma_misplaced(vma, 0, pin_params->alignment, 0)) {
737d718850SJani Nikula 			ret = i915_vma_unbind(vma);
747d718850SJani Nikula 			if (ret)
757d718850SJani Nikula 				continue;
767d718850SJani Nikula 		}
777d718850SJani Nikula 
78a89b7f72SVille Syrjälä 		ret = i915_vma_pin_ww(vma, &ww, 0, pin_params->alignment,
79a89b7f72SVille Syrjälä 				      PIN_GLOBAL);
807d718850SJani Nikula 		if (ret)
817d718850SJani Nikula 			continue;
827d718850SJani Nikula 	}
837d718850SJani Nikula 	if (ret) {
847d718850SJani Nikula 		vma = ERR_PTR(ret);
857d718850SJani Nikula 		goto err;
867d718850SJani Nikula 	}
877d718850SJani Nikula 
88a89b7f72SVille Syrjälä 	vma->display_alignment = max(vma->display_alignment,
89a89b7f72SVille Syrjälä 				     pin_params->alignment);
907d718850SJani Nikula 
917d718850SJani Nikula 	i915_gem_object_flush_if_display(obj);
927d718850SJani Nikula 
937d718850SJani Nikula 	i915_vma_get(vma);
94ef2b2e7cSVille Syrjälä 
95ef2b2e7cSVille Syrjälä 	/*
96ef2b2e7cSVille Syrjälä 	 * The DPT object contains only one vma, and there is no VT-d
97ef2b2e7cSVille Syrjälä 	 * guard, so the VMA's offset within the DPT is always 0.
98ef2b2e7cSVille Syrjälä 	 */
99ef2b2e7cSVille Syrjälä 	drm_WARN_ON(&i915->drm, i915_dpt_offset(vma));
1007d718850SJani Nikula err:
1016dc69ca3SVille Syrjälä 	atomic_dec(&i915->pending_fb_pin);
1027d718850SJani Nikula 
1037d718850SJani Nikula 	return vma;
1047d718850SJani Nikula }
1057d718850SJani Nikula 
106*24c100b8SVille Syrjälä static struct i915_vma *
1074fe8f832SVille Syrjälä intel_fb_pin_to_ggtt(struct drm_gem_object *_obj,
108a89b7f72SVille Syrjälä 		     const struct intel_fb_pin_params *pin_params,
109eb3dd964SVille Syrjälä 		     int *out_fence_id)
1107d718850SJani Nikula {
1114fe8f832SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(_obj->dev);
1127d718850SJani Nikula 	struct drm_i915_gem_object *obj = to_intel_bo(_obj);
113e5bec90aSJani Nikula 	intel_wakeref_t wakeref;
1147d718850SJani Nikula 	struct i915_gem_ww_ctx ww;
1157d718850SJani Nikula 	struct i915_vma *vma;
1167d718850SJani Nikula 	unsigned int pinctl;
1177d718850SJani Nikula 	int ret;
1187d718850SJani Nikula 
1193823bf01SJani Nikula 	if (drm_WARN_ON(&i915->drm, !i915_gem_object_is_framebuffer(obj)))
1207d718850SJani Nikula 		return ERR_PTR(-EINVAL);
1217d718850SJani Nikula 
122a89b7f72SVille Syrjälä 	if (drm_WARN_ON(&i915->drm, pin_params->alignment &&
123a89b7f72SVille Syrjälä 			!is_power_of_2(pin_params->alignment)))
1247d718850SJani Nikula 		return ERR_PTR(-EINVAL);
1257d718850SJani Nikula 
1267d718850SJani Nikula 	/*
1277d718850SJani Nikula 	 * Global gtt pte registers are special registers which actually forward
1287d718850SJani Nikula 	 * writes to a chunk of system memory. Which means that there is no risk
1297d718850SJani Nikula 	 * that the register values disappear as soon as we call
1307d718850SJani Nikula 	 * intel_runtime_pm_put(), so it is correct to wrap only the
1317d718850SJani Nikula 	 * pin/unpin/fence and not more.
1327d718850SJani Nikula 	 */
133e5bec90aSJani Nikula 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
1347d718850SJani Nikula 
1356dc69ca3SVille Syrjälä 	atomic_inc(&i915->pending_fb_pin);
1367d718850SJani Nikula 
1377d718850SJani Nikula 	pinctl = 0;
13841ff682eSVille Syrjälä 	/* PIN_MAPPABLE limits the address to GMADR size */
13919fa2194SVille Syrjälä 	if (pin_params->needs_low_address)
1407d718850SJani Nikula 		pinctl |= PIN_MAPPABLE;
1417d718850SJani Nikula 
1427d718850SJani Nikula 	i915_gem_ww_ctx_init(&ww, true);
1437d718850SJani Nikula retry:
1447d718850SJani Nikula 	ret = i915_gem_object_lock(obj, &ww);
14508a1df74SVille Syrjälä 	if (!ret && pin_params->needs_physical)
146a89b7f72SVille Syrjälä 		ret = i915_gem_object_attach_phys(obj, pin_params->phys_alignment);
1473823bf01SJani Nikula 	else if (!ret && HAS_LMEM(i915))
1487d718850SJani Nikula 		ret = i915_gem_object_migrate(obj, &ww, INTEL_REGION_LMEM_0);
1497d718850SJani Nikula 	if (!ret)
1507d718850SJani Nikula 		ret = i915_gem_object_pin_pages(obj);
1517d718850SJani Nikula 	if (ret)
1527d718850SJani Nikula 		goto err;
1537d718850SJani Nikula 
154a89b7f72SVille Syrjälä 	vma = i915_gem_object_pin_to_display_plane(obj, &ww,
155a89b7f72SVille Syrjälä 						   pin_params->alignment,
156a89b7f72SVille Syrjälä 						   pin_params->vtd_guard,
157a89b7f72SVille Syrjälä 						   pin_params->view, pinctl);
1587d718850SJani Nikula 	if (IS_ERR(vma)) {
1597d718850SJani Nikula 		ret = PTR_ERR(vma);
1607d718850SJani Nikula 		goto err_unpin;
1617d718850SJani Nikula 	}
1627d718850SJani Nikula 
163eb3dd964SVille Syrjälä 	if (out_fence_id)
164eb3dd964SVille Syrjälä 		*out_fence_id = -1;
165eb3dd964SVille Syrjälä 
166eb3dd964SVille Syrjälä 	if (out_fence_id && i915_vma_is_map_and_fenceable(vma)) {
1677d718850SJani Nikula 		/*
1687d718850SJani Nikula 		 * Install a fence for tiled scan-out. Pre-i965 always needs a
1697d718850SJani Nikula 		 * fence, whereas 965+ only requires a fence if using
1707d718850SJani Nikula 		 * framebuffer compression.  For simplicity, we always, when
1717d718850SJani Nikula 		 * possible, install a fence as the cost is not that onerous.
1727d718850SJani Nikula 		 *
1737d718850SJani Nikula 		 * If we fail to fence the tiled scanout, then either the
1747d718850SJani Nikula 		 * modeset will reject the change (which is highly unlikely as
1757d718850SJani Nikula 		 * the affected systems, all but one, do not have unmappable
1767d718850SJani Nikula 		 * space) or we will not be able to enable full powersaving
1777d718850SJani Nikula 		 * techniques (also likely not to apply due to various limits
1787d718850SJani Nikula 		 * FBC and the like impose on the size of the buffer, which
1797d718850SJani Nikula 		 * presumably we violated anyway with this unmappable buffer).
1807d718850SJani Nikula 		 * Anyway, it is presumably better to stumble onwards with
1817d718850SJani Nikula 		 * something and try to run the system in a "less than optimal"
1827d718850SJani Nikula 		 * mode that matches the user configuration.
1837d718850SJani Nikula 		 */
1847d718850SJani Nikula 		ret = i915_vma_pin_fence(vma);
185dfde353aSVille Syrjälä 		if (ret != 0 && pin_params->needs_fence) {
1867d718850SJani Nikula 			i915_vma_unpin(vma);
1877d718850SJani Nikula 			goto err_unpin;
1887d718850SJani Nikula 		}
1897d718850SJani Nikula 		ret = 0;
1907d718850SJani Nikula 
1917d718850SJani Nikula 		if (vma->fence)
192eb3dd964SVille Syrjälä 			*out_fence_id = vma->fence->id;
1937d718850SJani Nikula 	}
1947d718850SJani Nikula 
1957d718850SJani Nikula 	i915_vma_get(vma);
1967d718850SJani Nikula 
1977d718850SJani Nikula err_unpin:
1987d718850SJani Nikula 	i915_gem_object_unpin_pages(obj);
1997d718850SJani Nikula err:
2007d718850SJani Nikula 	if (ret == -EDEADLK) {
2017d718850SJani Nikula 		ret = i915_gem_ww_ctx_backoff(&ww);
2027d718850SJani Nikula 		if (!ret)
2037d718850SJani Nikula 			goto retry;
2047d718850SJani Nikula 	}
2057d718850SJani Nikula 	i915_gem_ww_ctx_fini(&ww);
2067d718850SJani Nikula 	if (ret)
2077d718850SJani Nikula 		vma = ERR_PTR(ret);
2087d718850SJani Nikula 
2096dc69ca3SVille Syrjälä 	atomic_dec(&i915->pending_fb_pin);
210e5bec90aSJani Nikula 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
2117d718850SJani Nikula 	return vma;
2127d718850SJani Nikula }
2137d718850SJani Nikula 
214eadbb52aSVille Syrjälä static void intel_fb_unpin_vma(struct i915_vma *vma, int fence_id)
2157d718850SJani Nikula {
216eb3dd964SVille Syrjälä 	if (fence_id >= 0)
2177d718850SJani Nikula 		i915_vma_unpin_fence(vma);
2187d718850SJani Nikula 	i915_vma_unpin(vma);
2197d718850SJani Nikula 	i915_vma_put(vma);
2207d718850SJani Nikula }
2217d718850SJani Nikula 
222da5c2fc6SVille Syrjälä static int i915_fb_pin_ggtt_pin(struct drm_gem_object *obj,
223da5c2fc6SVille Syrjälä 				const struct intel_fb_pin_params *pin_params,
224da5c2fc6SVille Syrjälä 				struct i915_vma **out_ggtt_vma,
225da5c2fc6SVille Syrjälä 				u32 *out_offset,
226da5c2fc6SVille Syrjälä 				int *out_fence_id)
227da5c2fc6SVille Syrjälä {
228da5c2fc6SVille Syrjälä 	struct i915_vma *ggtt_vma;
229da5c2fc6SVille Syrjälä 
230da5c2fc6SVille Syrjälä 	ggtt_vma = intel_fb_pin_to_ggtt(obj, pin_params, out_fence_id);
231da5c2fc6SVille Syrjälä 	if (IS_ERR(ggtt_vma))
232da5c2fc6SVille Syrjälä 		return PTR_ERR(ggtt_vma);
233da5c2fc6SVille Syrjälä 
234da5c2fc6SVille Syrjälä 	*out_ggtt_vma = ggtt_vma;
235da5c2fc6SVille Syrjälä 
236da5c2fc6SVille Syrjälä 	/*
237da5c2fc6SVille Syrjälä 	 * Pre-populate the dma address before we enter the vblank
238da5c2fc6SVille Syrjälä 	 * evade critical section as i915_gem_object_get_dma_address()
239da5c2fc6SVille Syrjälä 	 * will trigger might_sleep() even if it won't actually sleep,
240da5c2fc6SVille Syrjälä 	 * which is the case when the fb has already been pinned.
241da5c2fc6SVille Syrjälä 	 */
242da5c2fc6SVille Syrjälä 	if (pin_params->needs_physical)
243da5c2fc6SVille Syrjälä 		*out_offset = i915_gem_object_get_dma_address(to_intel_bo(obj), 0);
244da5c2fc6SVille Syrjälä 	else
245da5c2fc6SVille Syrjälä 		*out_offset = i915_ggtt_offset(ggtt_vma);
246da5c2fc6SVille Syrjälä 
247da5c2fc6SVille Syrjälä 	return 0;
248da5c2fc6SVille Syrjälä }
249da5c2fc6SVille Syrjälä 
250da5c2fc6SVille Syrjälä static void i915_fb_pin_ggtt_unpin(struct i915_vma *ggtt_vma,
251da5c2fc6SVille Syrjälä 				   int fence_id)
252da5c2fc6SVille Syrjälä {
253da5c2fc6SVille Syrjälä 	if (ggtt_vma)
254da5c2fc6SVille Syrjälä 		intel_fb_unpin_vma(ggtt_vma, fence_id);
255da5c2fc6SVille Syrjälä }
256da5c2fc6SVille Syrjälä 
257a8425a91SVille Syrjälä static int i915_fb_pin_dpt_pin(struct drm_gem_object *obj, struct intel_dpt *dpt,
258a8425a91SVille Syrjälä 			       const struct intel_fb_pin_params *pin_params,
259a8425a91SVille Syrjälä 			       struct i915_vma **out_dpt_vma,
260a8425a91SVille Syrjälä 			       struct i915_vma **out_ggtt_vma,
261a8425a91SVille Syrjälä 			       u32 *out_offset)
262a8425a91SVille Syrjälä {
263a8425a91SVille Syrjälä 	struct i915_vma *ggtt_vma, *dpt_vma;
264a8425a91SVille Syrjälä 
265a8425a91SVille Syrjälä 	WARN_ON(!dpt);
266a8425a91SVille Syrjälä 
267a8425a91SVille Syrjälä 	ggtt_vma = i915_dpt_pin_to_ggtt(dpt, pin_params->alignment / 512);
268a8425a91SVille Syrjälä 	if (IS_ERR(ggtt_vma))
269a8425a91SVille Syrjälä 		return PTR_ERR(ggtt_vma);
270a8425a91SVille Syrjälä 
271a8425a91SVille Syrjälä 	dpt_vma = intel_fb_pin_to_dpt(obj, dpt, pin_params);
272a8425a91SVille Syrjälä 	if (IS_ERR(dpt_vma)) {
273a8425a91SVille Syrjälä 		i915_dpt_unpin_from_ggtt(dpt);
274a8425a91SVille Syrjälä 		return PTR_ERR(dpt_vma);
275a8425a91SVille Syrjälä 	}
276a8425a91SVille Syrjälä 
277a8425a91SVille Syrjälä 	drm_WARN_ON(obj->dev, ggtt_vma == dpt_vma);
278a8425a91SVille Syrjälä 
279a8425a91SVille Syrjälä 	*out_ggtt_vma = ggtt_vma;
280a8425a91SVille Syrjälä 	*out_dpt_vma = dpt_vma;
281a8425a91SVille Syrjälä 
282a8425a91SVille Syrjälä 	*out_offset = i915_ggtt_offset(ggtt_vma);
283a8425a91SVille Syrjälä 
284a8425a91SVille Syrjälä 	return 0;
285a8425a91SVille Syrjälä }
286a8425a91SVille Syrjälä 
287a8425a91SVille Syrjälä static void i915_fb_pin_dpt_unpin(struct intel_dpt *dpt,
288a8425a91SVille Syrjälä 				  struct i915_vma *dpt_vma,
289a8425a91SVille Syrjälä 				  struct i915_vma *ggtt_vma)
290a8425a91SVille Syrjälä {
291a8425a91SVille Syrjälä 	WARN_ON(!dpt);
292a8425a91SVille Syrjälä 	WARN_ON(!!dpt_vma != !!ggtt_vma);
293a8425a91SVille Syrjälä 
294a8425a91SVille Syrjälä 	if (dpt_vma)
295a8425a91SVille Syrjälä 		intel_fb_unpin_vma(dpt_vma, -1);
296a8425a91SVille Syrjälä 	if (ggtt_vma)
297a8425a91SVille Syrjälä 		i915_dpt_unpin_from_ggtt(dpt);
298a8425a91SVille Syrjälä }
299a8425a91SVille Syrjälä 
300c2b4b607SVille Syrjälä static void i915_fb_pin_get_map(struct i915_vma *vma, struct iosys_map *map)
3017d718850SJani Nikula {
3027d718850SJani Nikula 	iosys_map_set_vaddr_iomem(map, i915_vma_get_iomap(vma));
3037d718850SJani Nikula }
304c2b4b607SVille Syrjälä 
305c2b4b607SVille Syrjälä const struct intel_display_fb_pin_interface i915_display_fb_pin_interface = {
306f225861aSVille Syrjälä 	.ggtt_pin = i915_fb_pin_ggtt_pin,
307f225861aSVille Syrjälä 	.ggtt_unpin = i915_fb_pin_ggtt_unpin,
308f225861aSVille Syrjälä 	.dpt_pin = i915_fb_pin_dpt_pin,
309f225861aSVille Syrjälä 	.dpt_unpin = i915_fb_pin_dpt_unpin,
310c2b4b607SVille Syrjälä 	.get_map = i915_fb_pin_get_map,
311c2b4b607SVille Syrjälä };
312