1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <drm/intel/display_parent_interface.h> 7 #include <drm/ttm/ttm_bo.h> 8 9 /* FIXME move the types to parent interface? */ 10 #include "i915_gtt_view_types.h" 11 12 /* FIXME move intel_remapped_info_size() & co. to parent interface? */ 13 #include "intel_fb.h" 14 15 #include "xe_bo.h" 16 #include "xe_device.h" 17 #include "xe_display_vma.h" 18 #include "xe_fb_pin.h" 19 #include "xe_ggtt.h" 20 #include "xe_pat.h" 21 #include "xe_pm.h" 22 #include "xe_vram_types.h" 23 24 static void 25 write_dpt_rotated(struct xe_bo *bo, struct iosys_map *map, u32 *dpt_ofs, u32 bo_ofs, 26 u32 width, u32 height, u32 src_stride, u32 dst_stride) 27 { 28 struct xe_device *xe = xe_bo_device(bo); 29 struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt; 30 u32 column, row; 31 u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE)); 32 33 /* TODO: Maybe rewrite so we can traverse the bo addresses sequentially, 34 * by writing dpt/ggtt in a different order? 35 */ 36 37 for (column = 0; column < width; column++) { 38 u32 src_idx = src_stride * (height - 1) + column + bo_ofs; 39 40 for (row = 0; row < height; row++) { 41 u64 addr = xe_bo_addr(bo, src_idx * XE_PAGE_SIZE, XE_PAGE_SIZE); 42 43 iosys_map_wr(map, *dpt_ofs, u64, pte | addr); 44 *dpt_ofs += 8; 45 src_idx -= src_stride; 46 } 47 48 /* The DE ignores the PTEs for the padding tiles */ 49 *dpt_ofs += (dst_stride - height) * 8; 50 } 51 52 /* Align to next page */ 53 *dpt_ofs = ALIGN(*dpt_ofs, 4096); 54 } 55 56 static unsigned int 57 write_dpt_padding(struct iosys_map *map, unsigned int dest, unsigned int pad) 58 { 59 /* The DE ignores the PTEs for the padding tiles */ 60 return dest + pad * sizeof(u64); 61 } 62 63 static unsigned int 64 write_dpt_remapped_linear(struct xe_bo *bo, struct iosys_map *map, 65 unsigned int dest, 66 const struct intel_remapped_plane_info *plane) 67 { 68 struct xe_device *xe = xe_bo_device(bo); 69 struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt; 70 const u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, 71 xe_cache_pat_idx(xe, XE_CACHE_NONE)); 72 unsigned int offset = plane->offset * XE_PAGE_SIZE; 73 unsigned int size = plane->size; 74 75 while (size--) { 76 u64 addr = xe_bo_addr(bo, offset, XE_PAGE_SIZE); 77 78 iosys_map_wr(map, dest, u64, addr | pte); 79 dest += sizeof(u64); 80 offset += XE_PAGE_SIZE; 81 } 82 83 return dest; 84 } 85 86 static unsigned int 87 write_dpt_remapped_tiled(struct xe_bo *bo, struct iosys_map *map, 88 unsigned int dest, 89 const struct intel_remapped_plane_info *plane) 90 { 91 struct xe_device *xe = xe_bo_device(bo); 92 struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt; 93 const u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, 94 xe_cache_pat_idx(xe, XE_CACHE_NONE)); 95 unsigned int offset, column, row; 96 97 for (row = 0; row < plane->height; row++) { 98 offset = (plane->offset + plane->src_stride * row) * 99 XE_PAGE_SIZE; 100 101 for (column = 0; column < plane->width; column++) { 102 u64 addr = xe_bo_addr(bo, offset, XE_PAGE_SIZE); 103 104 iosys_map_wr(map, dest, u64, addr | pte); 105 dest += sizeof(u64); 106 offset += XE_PAGE_SIZE; 107 } 108 109 dest = write_dpt_padding(map, dest, 110 plane->dst_stride - plane->width); 111 } 112 113 return dest; 114 } 115 116 static void 117 write_dpt_remapped(struct xe_bo *bo, 118 const struct intel_remapped_info *remap_info, 119 struct iosys_map *map) 120 { 121 unsigned int i, dest = 0; 122 123 for (i = 0; i < ARRAY_SIZE(remap_info->plane); i++) { 124 const struct intel_remapped_plane_info *plane = 125 &remap_info->plane[i]; 126 127 if (!plane->linear && !plane->width && !plane->height) 128 continue; 129 130 if (dest && remap_info->plane_alignment) { 131 const unsigned int index = dest / sizeof(u64); 132 const unsigned int pad = 133 ALIGN(index, remap_info->plane_alignment) - 134 index; 135 136 dest = write_dpt_padding(map, dest, pad); 137 } 138 139 if (plane->linear) 140 dest = write_dpt_remapped_linear(bo, map, dest, plane); 141 else 142 dest = write_dpt_remapped_tiled(bo, map, dest, plane); 143 } 144 } 145 146 static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj, 147 const struct intel_fb_pin_params *pin_params, 148 struct i915_vma *vma) 149 { 150 struct xe_device *xe = to_xe_device(obj->dev); 151 struct xe_tile *tile0 = xe_device_get_root_tile(xe); 152 struct xe_ggtt *ggtt = tile0->mem.ggtt; 153 const struct i915_gtt_view *view = pin_params->view; 154 struct xe_bo *bo = gem_to_xe_bo(obj), *dpt; 155 u32 dpt_size, size = bo->ttm.base.size; 156 157 if (view->type == I915_GTT_VIEW_NORMAL) 158 dpt_size = ALIGN(size / XE_PAGE_SIZE * 8, XE_PAGE_SIZE); 159 else if (view->type == I915_GTT_VIEW_REMAPPED) 160 dpt_size = ALIGN(intel_remapped_info_size(&view->remapped) * 8, 161 XE_PAGE_SIZE); 162 else 163 /* display uses 4K tiles instead of bytes here, convert to entries.. */ 164 dpt_size = ALIGN(intel_rotation_info_size(&view->rotated) * 8, 165 XE_PAGE_SIZE); 166 167 dpt = xe_bo_create_pin_map_at_novm(xe, tile0, 168 dpt_size, ~0ull, 169 ttm_bo_type_kernel, 170 XE_BO_FLAG_VRAM_IF_DGFX(tile0) | 171 XE_BO_FLAG_GGTT | 172 XE_BO_FLAG_PAGETABLE | 173 XE_BO_FLAG_FORCE_WC, 174 pin_params->alignment, false); 175 if (IS_ERR(dpt)) 176 return PTR_ERR(dpt); 177 178 if (view->type == I915_GTT_VIEW_NORMAL) { 179 u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE)); 180 u32 x; 181 182 for (x = 0; x < size / XE_PAGE_SIZE; x++) { 183 u64 addr = xe_bo_addr(bo, x * XE_PAGE_SIZE, XE_PAGE_SIZE); 184 185 iosys_map_wr(&dpt->vmap, x * 8, u64, pte | addr); 186 } 187 } else if (view->type == I915_GTT_VIEW_REMAPPED) { 188 write_dpt_remapped(bo, &view->remapped, &dpt->vmap); 189 } else { 190 const struct intel_rotation_info *rot_info = &view->rotated; 191 u32 i, dpt_ofs = 0; 192 193 for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++) 194 write_dpt_rotated(bo, &dpt->vmap, &dpt_ofs, 195 rot_info->plane[i].offset, 196 rot_info->plane[i].width, 197 rot_info->plane[i].height, 198 rot_info->plane[i].src_stride, 199 rot_info->plane[i].dst_stride); 200 } 201 202 vma->dpt = dpt; 203 vma->node = dpt->ggtt_node[tile0->id]; 204 205 /* Ensure DPT writes are flushed */ 206 xe_device_l2_flush(xe); 207 return 0; 208 } 209 210 static void 211 write_ggtt_rotated(struct xe_ggtt *ggtt, u32 *ggtt_ofs, 212 u64 pte_flags, 213 xe_ggtt_set_pte_fn write_pte, 214 struct xe_bo *bo, u32 bo_ofs, 215 u32 width, u32 height, u32 src_stride, u32 dst_stride) 216 { 217 u32 column, row; 218 219 for (column = 0; column < width; column++) { 220 u32 src_idx = src_stride * (height - 1) + column + bo_ofs; 221 222 for (row = 0; row < height; row++) { 223 u64 addr = xe_bo_addr(bo, src_idx * XE_PAGE_SIZE, XE_PAGE_SIZE); 224 225 write_pte(ggtt, *ggtt_ofs, pte_flags | addr); 226 *ggtt_ofs += XE_PAGE_SIZE; 227 src_idx -= src_stride; 228 } 229 230 /* The DE ignores the PTEs for the padding tiles */ 231 *ggtt_ofs += (dst_stride - height) * XE_PAGE_SIZE; 232 } 233 } 234 235 struct fb_rotate_args { 236 const struct i915_gtt_view *view; 237 struct xe_bo *bo; 238 }; 239 240 static void write_ggtt_rotated_node(struct xe_ggtt *ggtt, struct xe_ggtt_node *node, 241 u64 pte_flags, xe_ggtt_set_pte_fn write_pte, void *data) 242 { 243 struct fb_rotate_args *args = data; 244 struct xe_bo *bo = args->bo; 245 const struct intel_rotation_info *rot_info = &args->view->rotated; 246 u32 ggtt_ofs = xe_ggtt_node_addr(node); 247 248 for (u32 i = 0; i < ARRAY_SIZE(rot_info->plane); i++) 249 write_ggtt_rotated(ggtt, &ggtt_ofs, pte_flags, write_pte, 250 bo, rot_info->plane[i].offset, 251 rot_info->plane[i].width, 252 rot_info->plane[i].height, 253 rot_info->plane[i].src_stride, 254 rot_info->plane[i].dst_stride); 255 } 256 257 static int __xe_pin_fb_vma_ggtt(struct drm_gem_object *obj, 258 const struct intel_fb_pin_params *pin_params, 259 struct i915_vma *vma) 260 { 261 const struct i915_gtt_view *view = pin_params->view; 262 struct xe_bo *bo = gem_to_xe_bo(obj); 263 struct xe_device *xe = to_xe_device(obj->dev); 264 struct xe_tile *tile0 = xe_device_get_root_tile(xe); 265 struct xe_ggtt *ggtt = tile0->mem.ggtt; 266 u64 pte, size; 267 u32 align; 268 int ret = 0; 269 270 /* TODO: Consider sharing framebuffer mapping? 271 * embed i915_vma inside intel_framebuffer 272 */ 273 guard(xe_pm_runtime_noresume)(xe); 274 275 align = max(XE_PAGE_SIZE, pin_params->alignment); 276 if (xe_bo_is_vram(bo) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K) 277 align = max(align, SZ_64K); 278 279 /* Fast case, preallocated GGTT view? */ 280 if (bo->ggtt_node[tile0->id] && view->type == I915_GTT_VIEW_NORMAL) { 281 vma->node = bo->ggtt_node[tile0->id]; 282 return 0; 283 } 284 285 /* TODO: Consider sharing framebuffer mapping? 286 * embed i915_vma inside intel_framebuffer 287 */ 288 if (view->type == I915_GTT_VIEW_NORMAL) 289 size = xe_bo_size(bo); 290 else 291 /* display uses tiles instead of bytes here, so convert it back.. */ 292 size = intel_rotation_info_size(&view->rotated) * XE_PAGE_SIZE; 293 294 pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE)); 295 vma->node = xe_ggtt_insert_node_transform(ggtt, bo, pte, 296 ALIGN(size, align), align, 297 view->type == I915_GTT_VIEW_NORMAL ? 298 NULL : write_ggtt_rotated_node, 299 &(struct fb_rotate_args){view, bo}); 300 if (IS_ERR(vma->node)) 301 ret = PTR_ERR(vma->node); 302 303 return ret; 304 } 305 306 static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt, 307 const struct intel_fb_pin_params *pin_params) 308 { 309 struct xe_device *xe = to_xe_device(obj->dev); 310 struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); 311 struct xe_bo *bo = gem_to_xe_bo(obj); 312 struct xe_validation_ctx ctx; 313 struct drm_exec exec; 314 int ret = 0; 315 316 /* We reject creating !SCANOUT fb's, so this is weird.. */ 317 drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_FLAG_FORCE_WC) && 318 bo->ttm.type != ttm_bo_type_sg); 319 320 if (!vma) 321 return ERR_PTR(-ENODEV); 322 323 refcount_set(&vma->ref, 1); 324 if (IS_DGFX(to_xe_device(bo->ttm.base.dev)) && 325 pin_params->needs_cpu_lmem_access && 326 !(bo->flags & XE_BO_FLAG_NEEDS_CPU_ACCESS)) { 327 struct xe_vram_region *vram = xe_device_get_root_tile(xe)->mem.vram; 328 329 /* 330 * If we need to able to access the clear-color value stored in 331 * the buffer, then we require that such buffers are also CPU 332 * accessible. This is important on small-bar systems where 333 * only some subset of VRAM is CPU accessible. 334 */ 335 if (xe_vram_region_io_size(vram) < xe_vram_region_usable_size(vram)) { 336 ret = -EINVAL; 337 goto err; 338 } 339 } 340 341 /* 342 * Pin the framebuffer, we can't use xe_bo_(un)pin functions as the 343 * assumptions are incorrect for framebuffers 344 */ 345 xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {.interruptible = true}, 346 ret) { 347 ret = drm_exec_lock_obj(&exec, &bo->ttm.base); 348 drm_exec_retry_on_contention(&exec); 349 if (ret) 350 break; 351 352 if (IS_DGFX(xe)) 353 ret = xe_bo_migrate(bo, XE_PL_VRAM0, NULL, &exec); 354 else 355 ret = xe_bo_validate(bo, NULL, true, &exec); 356 drm_exec_retry_on_contention(&exec); 357 xe_validation_retry_on_oom(&ctx, &ret); 358 if (!ret) 359 ttm_bo_pin(&bo->ttm); 360 } 361 if (ret) 362 goto err; 363 364 vma->bo = bo; 365 if (is_dpt) 366 ret = __xe_pin_fb_vma_dpt(obj, pin_params, vma); 367 else 368 ret = __xe_pin_fb_vma_ggtt(obj, pin_params, vma); 369 if (ret) 370 goto err_unpin; 371 372 return vma; 373 374 err_unpin: 375 ttm_bo_reserve(&bo->ttm, false, false, NULL); 376 ttm_bo_unpin(&bo->ttm); 377 ttm_bo_unreserve(&bo->ttm); 378 err: 379 kfree(vma); 380 return ERR_PTR(ret); 381 } 382 383 static void __xe_unpin_fb_vma(struct i915_vma *vma) 384 { 385 u8 tile_id = xe_device_get_root_tile(xe_bo_device(vma->bo))->id; 386 387 if (!refcount_dec_and_test(&vma->ref)) 388 return; 389 390 if (vma->dpt) 391 xe_bo_unpin_map_no_vm(vma->dpt); 392 else if (vma->bo->ggtt_node[tile_id] != vma->node) 393 xe_ggtt_node_remove(vma->node, false); 394 395 ttm_bo_reserve(&vma->bo->ttm, false, false, NULL); 396 ttm_bo_unpin(&vma->bo->ttm); 397 ttm_bo_unreserve(&vma->bo->ttm); 398 kfree(vma); 399 } 400 401 int xe_fb_pin_ggtt_pin(struct drm_gem_object *obj, 402 const struct intel_fb_pin_params *pin_params, 403 struct i915_vma **out_ggtt_vma, 404 u32 *out_offset, 405 int *out_fence_id) 406 { 407 struct i915_vma *ggtt_vma; 408 409 ggtt_vma = __xe_pin_fb_vma(obj, false, pin_params); 410 if (IS_ERR(ggtt_vma)) 411 return PTR_ERR(ggtt_vma); 412 413 *out_ggtt_vma = ggtt_vma; 414 *out_offset = xe_ggtt_node_addr(ggtt_vma->node); 415 if (out_fence_id) 416 *out_fence_id = -1; 417 418 return 0; 419 } 420 421 static void xe_fb_pin_ggtt_unpin(struct i915_vma *ggtt_vma, 422 int fence_id) 423 { 424 WARN_ON(fence_id >= 0); 425 426 __xe_unpin_fb_vma(ggtt_vma); 427 } 428 429 static int xe_fb_pin_dpt_pin(struct drm_gem_object *obj, struct intel_dpt *dpt, 430 const struct intel_fb_pin_params *pin_params, 431 struct i915_vma **out_dpt_vma, 432 struct i915_vma **out_ggtt_vma, 433 u32 *out_offset) 434 { 435 struct i915_vma *ggtt_vma; 436 437 WARN_ON(dpt); 438 439 ggtt_vma = __xe_pin_fb_vma(obj, true, pin_params); 440 if (IS_ERR(ggtt_vma)) 441 return PTR_ERR(ggtt_vma); 442 443 *out_dpt_vma = NULL; /* not used on xe */ 444 *out_ggtt_vma = ggtt_vma; 445 *out_offset = xe_ggtt_node_addr(ggtt_vma->node); 446 447 return 0; 448 } 449 450 static void xe_fb_pin_dpt_unpin(struct intel_dpt *dpt, 451 struct i915_vma *dpt_vma, 452 struct i915_vma *ggtt_vma) 453 { 454 WARN_ON(dpt || dpt_vma); 455 456 __xe_unpin_fb_vma(ggtt_vma); 457 } 458 459 static struct i915_vma * 460 xe_fb_pin_reuse_vma(struct i915_vma *old_ggtt_vma, 461 struct drm_gem_object *old_obj, 462 const struct i915_gtt_view *old_view, 463 struct drm_gem_object *new_obj, 464 const struct i915_gtt_view *new_view, 465 u32 *out_offset) 466 { 467 if (old_ggtt_vma && old_obj == new_obj && 468 !memcmp(old_view, new_view, sizeof(*new_view))) { 469 refcount_inc(&old_ggtt_vma->ref); 470 471 *out_offset = xe_ggtt_node_addr(old_ggtt_vma->node); 472 473 return old_ggtt_vma; 474 } 475 476 return NULL; 477 } 478 479 static void xe_fb_pin_get_map(struct i915_vma *vma, struct iosys_map *map) 480 { 481 *map = vma->bo->vmap; 482 } 483 484 const struct intel_display_fb_pin_interface xe_display_fb_pin_interface = { 485 .ggtt_pin = xe_fb_pin_ggtt_pin, 486 .ggtt_unpin = xe_fb_pin_ggtt_unpin, 487 .dpt_pin = xe_fb_pin_dpt_pin, 488 .dpt_unpin = xe_fb_pin_dpt_unpin, 489 .reuse_vma = xe_fb_pin_reuse_vma, 490 .get_map = xe_fb_pin_get_map, 491 }; 492