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