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