1c6f73aabSFrançois Tigeot /* 2c6f73aabSFrançois Tigeot * Copyright 2008 Advanced Micro Devices, Inc. 3c6f73aabSFrançois Tigeot * Copyright 2008 Red Hat Inc. 4c6f73aabSFrançois Tigeot * Copyright 2009 Jerome Glisse. 5c6f73aabSFrançois Tigeot * 6c6f73aabSFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a 7c6f73aabSFrançois Tigeot * copy of this software and associated documentation files (the "Software"), 8c6f73aabSFrançois Tigeot * to deal in the Software without restriction, including without limitation 9c6f73aabSFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10c6f73aabSFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the 11c6f73aabSFrançois Tigeot * Software is furnished to do so, subject to the following conditions: 12c6f73aabSFrançois Tigeot * 13c6f73aabSFrançois Tigeot * The above copyright notice and this permission notice shall be included in 14c6f73aabSFrançois Tigeot * all copies or substantial portions of the Software. 15c6f73aabSFrançois Tigeot * 16c6f73aabSFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c6f73aabSFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c6f73aabSFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c6f73aabSFrançois Tigeot * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20c6f73aabSFrançois Tigeot * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21c6f73aabSFrançois Tigeot * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22c6f73aabSFrançois Tigeot * OTHER DEALINGS IN THE SOFTWARE. 23c6f73aabSFrançois Tigeot * 24c6f73aabSFrançois Tigeot * Authors: Dave Airlie 25c6f73aabSFrançois Tigeot * Alex Deucher 26c6f73aabSFrançois Tigeot * Jerome Glisse 27c6f73aabSFrançois Tigeot */ 28c6f73aabSFrançois Tigeot #include <drm/drmP.h> 2983b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h> 30c6f73aabSFrançois Tigeot #include "radeon.h" 31c6f73aabSFrançois Tigeot #ifdef TRACE_TODO 32c6f73aabSFrançois Tigeot #include "radeon_trace.h" 33c6f73aabSFrançois Tigeot #endif 34c6f73aabSFrançois Tigeot 35c6f73aabSFrançois Tigeot /* 36c6f73aabSFrançois Tigeot * GPUVM 37c6f73aabSFrançois Tigeot * GPUVM is similar to the legacy gart on older asics, however 38c6f73aabSFrançois Tigeot * rather than there being a single global gart table 39c6f73aabSFrançois Tigeot * for the entire GPU, there are multiple VM page tables active 40c6f73aabSFrançois Tigeot * at any given time. The VM page tables can contain a mix 41c6f73aabSFrançois Tigeot * vram pages and system memory pages and system memory pages 42c6f73aabSFrançois Tigeot * can be mapped as snooped (cached system pages) or unsnooped 43c6f73aabSFrançois Tigeot * (uncached system pages). 44c6f73aabSFrançois Tigeot * Each VM has an ID associated with it and there is a page table 45c6f73aabSFrançois Tigeot * associated with each VMID. When execting a command buffer, 46c6f73aabSFrançois Tigeot * the kernel tells the the ring what VMID to use for that command 47c6f73aabSFrançois Tigeot * buffer. VMIDs are allocated dynamically as commands are submitted. 48c6f73aabSFrançois Tigeot * The userspace drivers maintain their own address space and the kernel 49c6f73aabSFrançois Tigeot * sets up their pages tables accordingly when they submit their 50c6f73aabSFrançois Tigeot * command buffers and a VMID is assigned. 51c6f73aabSFrançois Tigeot * Cayman/Trinity support up to 8 active VMs at any given time; 52c6f73aabSFrançois Tigeot * SI supports 16. 53c6f73aabSFrançois Tigeot */ 54c6f73aabSFrançois Tigeot 55c6f73aabSFrançois Tigeot /** 56c6f73aabSFrançois Tigeot * radeon_vm_num_pde - return the number of page directory entries 57c6f73aabSFrançois Tigeot * 58c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 59c6f73aabSFrançois Tigeot * 60c6f73aabSFrançois Tigeot * Calculate the number of page directory entries (cayman+). 61c6f73aabSFrançois Tigeot */ 62c6f73aabSFrançois Tigeot static unsigned radeon_vm_num_pdes(struct radeon_device *rdev) 63c6f73aabSFrançois Tigeot { 64c6f73aabSFrançois Tigeot return rdev->vm_manager.max_pfn >> radeon_vm_block_size; 65c6f73aabSFrançois Tigeot } 66c6f73aabSFrançois Tigeot 67c6f73aabSFrançois Tigeot /** 68c6f73aabSFrançois Tigeot * radeon_vm_directory_size - returns the size of the page directory in bytes 69c6f73aabSFrançois Tigeot * 70c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 71c6f73aabSFrançois Tigeot * 72c6f73aabSFrançois Tigeot * Calculate the size of the page directory in bytes (cayman+). 73c6f73aabSFrançois Tigeot */ 74c6f73aabSFrançois Tigeot static unsigned radeon_vm_directory_size(struct radeon_device *rdev) 75c6f73aabSFrançois Tigeot { 76c6f73aabSFrançois Tigeot return RADEON_GPU_PAGE_ALIGN(radeon_vm_num_pdes(rdev) * 8); 77c6f73aabSFrançois Tigeot } 78c6f73aabSFrançois Tigeot 79c6f73aabSFrançois Tigeot /** 80c6f73aabSFrançois Tigeot * radeon_vm_manager_init - init the vm manager 81c6f73aabSFrançois Tigeot * 82c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 83c6f73aabSFrançois Tigeot * 84c6f73aabSFrançois Tigeot * Init the vm manager (cayman+). 85c6f73aabSFrançois Tigeot * Returns 0 for success, error for failure. 86c6f73aabSFrançois Tigeot */ 87c6f73aabSFrançois Tigeot int radeon_vm_manager_init(struct radeon_device *rdev) 88c6f73aabSFrançois Tigeot { 89c6f73aabSFrançois Tigeot int r; 90c6f73aabSFrançois Tigeot 91c6f73aabSFrançois Tigeot if (!rdev->vm_manager.enabled) { 92c6f73aabSFrançois Tigeot r = radeon_asic_vm_init(rdev); 93c6f73aabSFrançois Tigeot if (r) 94c6f73aabSFrançois Tigeot return r; 95c6f73aabSFrançois Tigeot 96c6f73aabSFrançois Tigeot rdev->vm_manager.enabled = true; 97c6f73aabSFrançois Tigeot } 98c6f73aabSFrançois Tigeot return 0; 99c6f73aabSFrançois Tigeot } 100c6f73aabSFrançois Tigeot 101c6f73aabSFrançois Tigeot /** 102c6f73aabSFrançois Tigeot * radeon_vm_manager_fini - tear down the vm manager 103c6f73aabSFrançois Tigeot * 104c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 105c6f73aabSFrançois Tigeot * 106c6f73aabSFrançois Tigeot * Tear down the VM manager (cayman+). 107c6f73aabSFrançois Tigeot */ 108c6f73aabSFrançois Tigeot void radeon_vm_manager_fini(struct radeon_device *rdev) 109c6f73aabSFrançois Tigeot { 110c6f73aabSFrançois Tigeot int i; 111c6f73aabSFrançois Tigeot 112c6f73aabSFrançois Tigeot if (!rdev->vm_manager.enabled) 113c6f73aabSFrançois Tigeot return; 114c6f73aabSFrançois Tigeot 115c6f73aabSFrançois Tigeot for (i = 0; i < RADEON_NUM_VM; ++i) 116c6f73aabSFrançois Tigeot radeon_fence_unref(&rdev->vm_manager.active[i]); 117c6f73aabSFrançois Tigeot radeon_asic_vm_fini(rdev); 118c6f73aabSFrançois Tigeot rdev->vm_manager.enabled = false; 119c6f73aabSFrançois Tigeot } 120c6f73aabSFrançois Tigeot 121c6f73aabSFrançois Tigeot /** 122c6f73aabSFrançois Tigeot * radeon_vm_get_bos - add the vm BOs to a validation list 123c6f73aabSFrançois Tigeot * 124c6f73aabSFrançois Tigeot * @vm: vm providing the BOs 125c6f73aabSFrançois Tigeot * @head: head of validation list 126c6f73aabSFrançois Tigeot * 127c6f73aabSFrançois Tigeot * Add the page directory to the list of BOs to 128c6f73aabSFrançois Tigeot * validate for command submission (cayman+). 129c6f73aabSFrançois Tigeot */ 130ee479021SImre Vadász struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev, 131c6f73aabSFrançois Tigeot struct radeon_vm *vm, 132c6f73aabSFrançois Tigeot struct list_head *head) 133c6f73aabSFrançois Tigeot { 134ee479021SImre Vadász struct radeon_cs_reloc *list; 135c6f73aabSFrançois Tigeot unsigned i, idx; 136c6f73aabSFrançois Tigeot 137591d5043SFrançois Tigeot list = drm_malloc_ab(vm->max_pde_used + 2, 138ee479021SImre Vadász sizeof(struct radeon_cs_reloc)); 139c6f73aabSFrançois Tigeot if (!list) 140c6f73aabSFrançois Tigeot return NULL; 141c6f73aabSFrançois Tigeot 142c6f73aabSFrançois Tigeot /* add the vm page table to the list */ 143ee479021SImre Vadász list[0].gobj = NULL; 144c6f73aabSFrançois Tigeot list[0].robj = vm->page_directory; 145c6f73aabSFrançois Tigeot list[0].prefered_domains = RADEON_GEM_DOMAIN_VRAM; 146c6f73aabSFrançois Tigeot list[0].allowed_domains = RADEON_GEM_DOMAIN_VRAM; 147c6f73aabSFrançois Tigeot list[0].tv.bo = &vm->page_directory->tbo; 148*1cfef1a5SFrançois Tigeot list[0].tv.shared = false; 149c6f73aabSFrançois Tigeot list[0].tiling_flags = 0; 150ee479021SImre Vadász list[0].handle = 0; 151c6f73aabSFrançois Tigeot list_add(&list[0].tv.head, head); 152c6f73aabSFrançois Tigeot 153c6f73aabSFrançois Tigeot for (i = 0, idx = 1; i <= vm->max_pde_used; i++) { 154c6f73aabSFrançois Tigeot if (!vm->page_tables[i].bo) 155c6f73aabSFrançois Tigeot continue; 156c6f73aabSFrançois Tigeot 157ee479021SImre Vadász list[idx].gobj = NULL; 158c6f73aabSFrançois Tigeot list[idx].robj = vm->page_tables[i].bo; 159c6f73aabSFrançois Tigeot list[idx].prefered_domains = RADEON_GEM_DOMAIN_VRAM; 160c6f73aabSFrançois Tigeot list[idx].allowed_domains = RADEON_GEM_DOMAIN_VRAM; 161c6f73aabSFrançois Tigeot list[idx].tv.bo = &list[idx].robj->tbo; 162*1cfef1a5SFrançois Tigeot list[idx].tv.shared = false; 163c6f73aabSFrançois Tigeot list[idx].tiling_flags = 0; 164ee479021SImre Vadász list[idx].handle = 0; 165c6f73aabSFrançois Tigeot list_add(&list[idx++].tv.head, head); 166c6f73aabSFrançois Tigeot } 167c6f73aabSFrançois Tigeot 168c6f73aabSFrançois Tigeot return list; 169c6f73aabSFrançois Tigeot } 170c6f73aabSFrançois Tigeot 171c6f73aabSFrançois Tigeot /** 172c6f73aabSFrançois Tigeot * radeon_vm_grab_id - allocate the next free VMID 173c6f73aabSFrançois Tigeot * 174c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 175c6f73aabSFrançois Tigeot * @vm: vm to allocate id for 176c6f73aabSFrançois Tigeot * @ring: ring we want to submit job to 177c6f73aabSFrançois Tigeot * 178c6f73aabSFrançois Tigeot * Allocate an id for the vm (cayman+). 179c6f73aabSFrançois Tigeot * Returns the fence we need to sync to (if any). 180c6f73aabSFrançois Tigeot * 181c6f73aabSFrançois Tigeot * Global and local mutex must be locked! 182c6f73aabSFrançois Tigeot */ 183c6f73aabSFrançois Tigeot struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev, 184c6f73aabSFrançois Tigeot struct radeon_vm *vm, int ring) 185c6f73aabSFrançois Tigeot { 186c6f73aabSFrançois Tigeot struct radeon_fence *best[RADEON_NUM_RINGS] = {}; 187c6f73aabSFrançois Tigeot unsigned choices[2] = {}; 188c6f73aabSFrançois Tigeot unsigned i; 189c6f73aabSFrançois Tigeot 190c6f73aabSFrançois Tigeot /* check if the id is still valid */ 191c6f73aabSFrançois Tigeot if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id]) 192c6f73aabSFrançois Tigeot return NULL; 193c6f73aabSFrançois Tigeot 194c6f73aabSFrançois Tigeot /* we definately need to flush */ 195c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->last_flush); 196c6f73aabSFrançois Tigeot 197c6f73aabSFrançois Tigeot /* skip over VMID 0, since it is the system VM */ 198c6f73aabSFrançois Tigeot for (i = 1; i < rdev->vm_manager.nvm; ++i) { 199c6f73aabSFrançois Tigeot struct radeon_fence *fence = rdev->vm_manager.active[i]; 200c6f73aabSFrançois Tigeot 201c6f73aabSFrançois Tigeot if (fence == NULL) { 202c6f73aabSFrançois Tigeot /* found a free one */ 203c6f73aabSFrançois Tigeot vm->id = i; 204c6f73aabSFrançois Tigeot #ifdef TRACE_TODO 205c6f73aabSFrançois Tigeot trace_radeon_vm_grab_id(vm->id, ring); 206c6f73aabSFrançois Tigeot #endif 207c6f73aabSFrançois Tigeot return NULL; 208c6f73aabSFrançois Tigeot } 209c6f73aabSFrançois Tigeot 210c6f73aabSFrançois Tigeot if (radeon_fence_is_earlier(fence, best[fence->ring])) { 211c6f73aabSFrançois Tigeot best[fence->ring] = fence; 212c6f73aabSFrançois Tigeot choices[fence->ring == ring ? 0 : 1] = i; 213c6f73aabSFrançois Tigeot } 214c6f73aabSFrançois Tigeot } 215c6f73aabSFrançois Tigeot 216c6f73aabSFrançois Tigeot for (i = 0; i < 2; ++i) { 217c6f73aabSFrançois Tigeot if (choices[i]) { 218c6f73aabSFrançois Tigeot vm->id = choices[i]; 219c6f73aabSFrançois Tigeot #ifdef TRACE_TODO 220c6f73aabSFrançois Tigeot trace_radeon_vm_grab_id(vm->id, ring); 221c6f73aabSFrançois Tigeot #endif 222c6f73aabSFrançois Tigeot return rdev->vm_manager.active[choices[i]]; 223c6f73aabSFrançois Tigeot } 224c6f73aabSFrançois Tigeot } 225c6f73aabSFrançois Tigeot 226c6f73aabSFrançois Tigeot /* should never happen */ 227c6f73aabSFrançois Tigeot BUG(); 228c6f73aabSFrançois Tigeot return NULL; 229c6f73aabSFrançois Tigeot } 230c6f73aabSFrançois Tigeot 231c6f73aabSFrançois Tigeot /** 232c6f73aabSFrançois Tigeot * radeon_vm_flush - hardware flush the vm 233c6f73aabSFrançois Tigeot * 234c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 235c6f73aabSFrançois Tigeot * @vm: vm we want to flush 236c6f73aabSFrançois Tigeot * @ring: ring to use for flush 237c6f73aabSFrançois Tigeot * 238c6f73aabSFrançois Tigeot * Flush the vm (cayman+). 239c6f73aabSFrançois Tigeot * 240c6f73aabSFrançois Tigeot * Global and local mutex must be locked! 241c6f73aabSFrançois Tigeot */ 242c6f73aabSFrançois Tigeot void radeon_vm_flush(struct radeon_device *rdev, 243c6f73aabSFrançois Tigeot struct radeon_vm *vm, 244c6f73aabSFrançois Tigeot int ring) 245c6f73aabSFrançois Tigeot { 246c6f73aabSFrançois Tigeot uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); 247c6f73aabSFrançois Tigeot 248c6f73aabSFrançois Tigeot /* if we can't remember our last VM flush then flush now! */ 249*1cfef1a5SFrançois Tigeot if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { 250c6f73aabSFrançois Tigeot #ifdef TRACE_TODO 251c6f73aabSFrançois Tigeot trace_radeon_vm_flush(pd_addr, ring, vm->id); 252c6f73aabSFrançois Tigeot #endif 253c6f73aabSFrançois Tigeot vm->pd_gpu_addr = pd_addr; 254ee479021SImre Vadász radeon_ring_vm_flush(rdev, ring, vm); 255c6f73aabSFrançois Tigeot } 256c6f73aabSFrançois Tigeot } 257c6f73aabSFrançois Tigeot 258c6f73aabSFrançois Tigeot /** 259c6f73aabSFrançois Tigeot * radeon_vm_fence - remember fence for vm 260c6f73aabSFrançois Tigeot * 261c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 262c6f73aabSFrançois Tigeot * @vm: vm we want to fence 263c6f73aabSFrançois Tigeot * @fence: fence to remember 264c6f73aabSFrançois Tigeot * 265c6f73aabSFrançois Tigeot * Fence the vm (cayman+). 266c6f73aabSFrançois Tigeot * Set the fence used to protect page table and id. 267c6f73aabSFrançois Tigeot * 268c6f73aabSFrançois Tigeot * Global and local mutex must be locked! 269c6f73aabSFrançois Tigeot */ 270c6f73aabSFrançois Tigeot void radeon_vm_fence(struct radeon_device *rdev, 271c6f73aabSFrançois Tigeot struct radeon_vm *vm, 272c6f73aabSFrançois Tigeot struct radeon_fence *fence) 273c6f73aabSFrançois Tigeot { 274c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->fence); 275c6f73aabSFrançois Tigeot vm->fence = radeon_fence_ref(fence); 276c6f73aabSFrançois Tigeot 277c6f73aabSFrançois Tigeot radeon_fence_unref(&rdev->vm_manager.active[vm->id]); 278c6f73aabSFrançois Tigeot rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence); 279c6f73aabSFrançois Tigeot 280c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->last_id_use); 281c6f73aabSFrançois Tigeot vm->last_id_use = radeon_fence_ref(fence); 282c6f73aabSFrançois Tigeot 283c6f73aabSFrançois Tigeot /* we just flushed the VM, remember that */ 284c6f73aabSFrançois Tigeot if (!vm->last_flush) 285c6f73aabSFrançois Tigeot vm->last_flush = radeon_fence_ref(fence); 286c6f73aabSFrançois Tigeot } 287c6f73aabSFrançois Tigeot 288c6f73aabSFrançois Tigeot /** 289c6f73aabSFrançois Tigeot * radeon_vm_bo_find - find the bo_va for a specific vm & bo 290c6f73aabSFrançois Tigeot * 291c6f73aabSFrançois Tigeot * @vm: requested vm 292c6f73aabSFrançois Tigeot * @bo: requested buffer object 293c6f73aabSFrançois Tigeot * 294c6f73aabSFrançois Tigeot * Find @bo inside the requested vm (cayman+). 295c6f73aabSFrançois Tigeot * Search inside the @bos vm list for the requested vm 296c6f73aabSFrançois Tigeot * Returns the found bo_va or NULL if none is found 297c6f73aabSFrançois Tigeot * 298c6f73aabSFrançois Tigeot * Object has to be reserved! 299c6f73aabSFrançois Tigeot */ 300c6f73aabSFrançois Tigeot struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm, 301c6f73aabSFrançois Tigeot struct radeon_bo *bo) 302c6f73aabSFrançois Tigeot { 303c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va; 304c6f73aabSFrançois Tigeot 305c6f73aabSFrançois Tigeot list_for_each_entry(bo_va, &bo->va, bo_list) { 306c6f73aabSFrançois Tigeot if (bo_va->vm == vm) { 307c6f73aabSFrançois Tigeot return bo_va; 308c6f73aabSFrançois Tigeot } 309c6f73aabSFrançois Tigeot } 310c6f73aabSFrançois Tigeot return NULL; 311c6f73aabSFrançois Tigeot } 312c6f73aabSFrançois Tigeot 313c6f73aabSFrançois Tigeot /** 314c6f73aabSFrançois Tigeot * radeon_vm_bo_add - add a bo to a specific vm 315c6f73aabSFrançois Tigeot * 316c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 317c6f73aabSFrançois Tigeot * @vm: requested vm 318c6f73aabSFrançois Tigeot * @bo: radeon buffer object 319c6f73aabSFrançois Tigeot * 320c6f73aabSFrançois Tigeot * Add @bo into the requested vm (cayman+). 321c6f73aabSFrançois Tigeot * Add @bo to the list of bos associated with the vm 322c6f73aabSFrançois Tigeot * Returns newly added bo_va or NULL for failure 323c6f73aabSFrançois Tigeot * 324c6f73aabSFrançois Tigeot * Object has to be reserved! 325c6f73aabSFrançois Tigeot */ 326c6f73aabSFrançois Tigeot struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, 327c6f73aabSFrançois Tigeot struct radeon_vm *vm, 328c6f73aabSFrançois Tigeot struct radeon_bo *bo) 329c6f73aabSFrançois Tigeot { 330c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va; 331c6f73aabSFrançois Tigeot 332c6f73aabSFrançois Tigeot bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); 333c6f73aabSFrançois Tigeot if (bo_va == NULL) { 334c6f73aabSFrançois Tigeot return NULL; 335c6f73aabSFrançois Tigeot } 336c6f73aabSFrançois Tigeot bo_va->vm = vm; 337c6f73aabSFrançois Tigeot bo_va->bo = bo; 338*1cfef1a5SFrançois Tigeot bo_va->it.start = 0; 339*1cfef1a5SFrançois Tigeot bo_va->it.last = 0; 340c6f73aabSFrançois Tigeot bo_va->flags = 0; 341c6f73aabSFrançois Tigeot bo_va->addr = 0; 342c6f73aabSFrançois Tigeot bo_va->ref_count = 1; 343c6f73aabSFrançois Tigeot INIT_LIST_HEAD(&bo_va->bo_list); 344c6f73aabSFrançois Tigeot INIT_LIST_HEAD(&bo_va->vm_status); 345c6f73aabSFrançois Tigeot 346ee479021SImre Vadász lockmgr(&vm->mutex, LK_EXCLUSIVE); 347c6f73aabSFrançois Tigeot list_add_tail(&bo_va->bo_list, &bo->va); 348ee479021SImre Vadász lockmgr(&vm->mutex, LK_RELEASE); 349c6f73aabSFrançois Tigeot 350c6f73aabSFrançois Tigeot return bo_va; 351c6f73aabSFrançois Tigeot } 352c6f73aabSFrançois Tigeot 353c6f73aabSFrançois Tigeot /** 354c6f73aabSFrançois Tigeot * radeon_vm_set_pages - helper to call the right asic function 355c6f73aabSFrançois Tigeot * 356c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 357c6f73aabSFrançois Tigeot * @ib: indirect buffer to fill with commands 358c6f73aabSFrançois Tigeot * @pe: addr of the page entry 359c6f73aabSFrançois Tigeot * @addr: dst addr to write into pe 360c6f73aabSFrançois Tigeot * @count: number of page entries to update 361c6f73aabSFrançois Tigeot * @incr: increase next addr by incr bytes 362c6f73aabSFrançois Tigeot * @flags: hw access flags 363c6f73aabSFrançois Tigeot * 364c6f73aabSFrançois Tigeot * Traces the parameters and calls the right asic functions 365c6f73aabSFrançois Tigeot * to setup the page table using the DMA. 366c6f73aabSFrançois Tigeot */ 367c6f73aabSFrançois Tigeot static void radeon_vm_set_pages(struct radeon_device *rdev, 368c6f73aabSFrançois Tigeot struct radeon_ib *ib, 369c6f73aabSFrançois Tigeot uint64_t pe, 370c6f73aabSFrançois Tigeot uint64_t addr, unsigned count, 371c6f73aabSFrançois Tigeot uint32_t incr, uint32_t flags) 372c6f73aabSFrançois Tigeot { 373c6f73aabSFrançois Tigeot #ifdef TRACE_TODO 374c6f73aabSFrançois Tigeot trace_radeon_vm_set_page(pe, addr, count, incr, flags); 375c6f73aabSFrançois Tigeot #endif 376c6f73aabSFrançois Tigeot 377c6f73aabSFrançois Tigeot if ((flags & R600_PTE_GART_MASK) == R600_PTE_GART_MASK) { 378c6f73aabSFrançois Tigeot uint64_t src = rdev->gart.table_addr + (addr >> 12) * 8; 379c6f73aabSFrançois Tigeot radeon_asic_vm_copy_pages(rdev, ib, pe, src, count); 380c6f73aabSFrançois Tigeot 381c6f73aabSFrançois Tigeot } else if ((flags & R600_PTE_SYSTEM) || (count < 3)) { 382c6f73aabSFrançois Tigeot radeon_asic_vm_write_pages(rdev, ib, pe, addr, 383c6f73aabSFrançois Tigeot count, incr, flags); 384c6f73aabSFrançois Tigeot 385c6f73aabSFrançois Tigeot } else { 386c6f73aabSFrançois Tigeot radeon_asic_vm_set_pages(rdev, ib, pe, addr, 387c6f73aabSFrançois Tigeot count, incr, flags); 388c6f73aabSFrançois Tigeot } 389c6f73aabSFrançois Tigeot } 390c6f73aabSFrançois Tigeot 391c6f73aabSFrançois Tigeot /** 392c6f73aabSFrançois Tigeot * radeon_vm_clear_bo - initially clear the page dir/table 393c6f73aabSFrançois Tigeot * 394c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 395c6f73aabSFrançois Tigeot * @bo: bo to clear 396c6f73aabSFrançois Tigeot */ 397c6f73aabSFrançois Tigeot static int radeon_vm_clear_bo(struct radeon_device *rdev, 398c6f73aabSFrançois Tigeot struct radeon_bo *bo) 399c6f73aabSFrançois Tigeot { 400c6f73aabSFrançois Tigeot struct ttm_validate_buffer tv; 401c6f73aabSFrançois Tigeot struct ww_acquire_ctx ticket; 402c6f73aabSFrançois Tigeot struct list_head head; 403c6f73aabSFrançois Tigeot struct radeon_ib ib; 404c6f73aabSFrançois Tigeot unsigned entries; 405c6f73aabSFrançois Tigeot uint64_t addr; 406c6f73aabSFrançois Tigeot int r; 407c6f73aabSFrançois Tigeot 408c6f73aabSFrançois Tigeot memset(&tv, 0, sizeof(tv)); 409c6f73aabSFrançois Tigeot tv.bo = &bo->tbo; 410*1cfef1a5SFrançois Tigeot tv.shared = false; 411c6f73aabSFrançois Tigeot 412c6f73aabSFrançois Tigeot INIT_LIST_HEAD(&head); 413c6f73aabSFrançois Tigeot list_add(&tv.head, &head); 414c6f73aabSFrançois Tigeot 415*1cfef1a5SFrançois Tigeot r = ttm_eu_reserve_buffers(&ticket, &head, true); 416c6f73aabSFrançois Tigeot if (r) 417c6f73aabSFrançois Tigeot return r; 418c6f73aabSFrançois Tigeot 419c6f73aabSFrançois Tigeot r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); 420c6f73aabSFrançois Tigeot if (r) 421c6f73aabSFrançois Tigeot goto error; 422c6f73aabSFrançois Tigeot 423c6f73aabSFrançois Tigeot addr = radeon_bo_gpu_offset(bo); 424c6f73aabSFrançois Tigeot entries = radeon_bo_size(bo) / 8; 425c6f73aabSFrançois Tigeot 426c6f73aabSFrançois Tigeot r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, 256); 427c6f73aabSFrançois Tigeot if (r) 428c6f73aabSFrançois Tigeot goto error; 429c6f73aabSFrançois Tigeot 430c6f73aabSFrançois Tigeot ib.length_dw = 0; 431c6f73aabSFrançois Tigeot 432c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, &ib, addr, 0, entries, 0, 0); 433c6f73aabSFrançois Tigeot radeon_asic_vm_pad_ib(rdev, &ib); 434c6f73aabSFrançois Tigeot WARN_ON(ib.length_dw > 64); 435c6f73aabSFrançois Tigeot 436c6f73aabSFrançois Tigeot r = radeon_ib_schedule(rdev, &ib, NULL, false); 437c6f73aabSFrançois Tigeot if (r) 438c6f73aabSFrançois Tigeot goto error; 439c6f73aabSFrançois Tigeot 440*1cfef1a5SFrançois Tigeot ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base); 441c6f73aabSFrançois Tigeot radeon_ib_free(rdev, &ib); 442c6f73aabSFrançois Tigeot 443c6f73aabSFrançois Tigeot return 0; 444c6f73aabSFrançois Tigeot 445c6f73aabSFrançois Tigeot error: 446c6f73aabSFrançois Tigeot ttm_eu_backoff_reservation(&ticket, &head); 447c6f73aabSFrançois Tigeot return r; 448c6f73aabSFrançois Tigeot } 449c6f73aabSFrançois Tigeot 450c6f73aabSFrançois Tigeot /** 451c6f73aabSFrançois Tigeot * radeon_vm_bo_set_addr - set bos virtual address inside a vm 452c6f73aabSFrançois Tigeot * 453c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 454c6f73aabSFrançois Tigeot * @bo_va: bo_va to store the address 455c6f73aabSFrançois Tigeot * @soffset: requested offset of the buffer in the VM address space 456c6f73aabSFrançois Tigeot * @flags: attributes of pages (read/write/valid/etc.) 457c6f73aabSFrançois Tigeot * 458c6f73aabSFrançois Tigeot * Set offset of @bo_va (cayman+). 459c6f73aabSFrançois Tigeot * Validate and set the offset requested within the vm address space. 460c6f73aabSFrançois Tigeot * Returns 0 for success, error for failure. 461c6f73aabSFrançois Tigeot * 462ee479021SImre Vadász * Object has to be reserved! 463c6f73aabSFrançois Tigeot */ 464c6f73aabSFrançois Tigeot int radeon_vm_bo_set_addr(struct radeon_device *rdev, 465c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va, 466c6f73aabSFrançois Tigeot uint64_t soffset, 467c6f73aabSFrançois Tigeot uint32_t flags) 468c6f73aabSFrançois Tigeot { 469c6f73aabSFrançois Tigeot uint64_t size = radeon_bo_size(bo_va->bo); 470c6f73aabSFrançois Tigeot struct radeon_vm *vm = bo_va->vm; 471c6f73aabSFrançois Tigeot unsigned last_pfn, pt_idx; 472*1cfef1a5SFrançois Tigeot uint64_t eoffset; 473c6f73aabSFrançois Tigeot int r; 474c6f73aabSFrançois Tigeot 475c6f73aabSFrançois Tigeot if (soffset) { 476c6f73aabSFrançois Tigeot /* make sure object fit at this offset */ 477c6f73aabSFrançois Tigeot eoffset = soffset + size; 478c6f73aabSFrançois Tigeot if (soffset >= eoffset) { 479ee479021SImre Vadász return -EINVAL; 480c6f73aabSFrançois Tigeot } 481c6f73aabSFrançois Tigeot 482c6f73aabSFrançois Tigeot last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; 483c6f73aabSFrançois Tigeot if (last_pfn > rdev->vm_manager.max_pfn) { 484c6f73aabSFrançois Tigeot dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", 485c6f73aabSFrançois Tigeot last_pfn, rdev->vm_manager.max_pfn); 486ee479021SImre Vadász return -EINVAL; 487c6f73aabSFrançois Tigeot } 488c6f73aabSFrançois Tigeot 489c6f73aabSFrançois Tigeot } else { 490c6f73aabSFrançois Tigeot eoffset = last_pfn = 0; 491c6f73aabSFrançois Tigeot } 492c6f73aabSFrançois Tigeot 493*1cfef1a5SFrançois Tigeot mutex_lock(&vm->mutex); 494*1cfef1a5SFrançois Tigeot if (bo_va->it.start || bo_va->it.last) { 495*1cfef1a5SFrançois Tigeot if (bo_va->addr) { 496c6f73aabSFrançois Tigeot /* add a clone of the bo_va to clear the old address */ 497*1cfef1a5SFrançois Tigeot struct radeon_bo_va *tmp; 498c6f73aabSFrançois Tigeot tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); 499*1cfef1a5SFrançois Tigeot tmp->it.start = bo_va->it.start; 500*1cfef1a5SFrançois Tigeot tmp->it.last = bo_va->it.last; 501c6f73aabSFrançois Tigeot tmp->vm = vm; 502*1cfef1a5SFrançois Tigeot tmp->addr = bo_va->addr; 503c6f73aabSFrançois Tigeot list_add(&tmp->vm_status, &vm->freed); 504c6f73aabSFrançois Tigeot } 505c6f73aabSFrançois Tigeot 506*1cfef1a5SFrançois Tigeot interval_tree_remove(&bo_va->it, &vm->va); 507*1cfef1a5SFrançois Tigeot bo_va->it.start = 0; 508*1cfef1a5SFrançois Tigeot bo_va->it.last = 0; 509*1cfef1a5SFrançois Tigeot } 510*1cfef1a5SFrançois Tigeot 511*1cfef1a5SFrançois Tigeot soffset /= RADEON_GPU_PAGE_SIZE; 512*1cfef1a5SFrançois Tigeot eoffset /= RADEON_GPU_PAGE_SIZE; 513*1cfef1a5SFrançois Tigeot if (soffset || eoffset) { 514*1cfef1a5SFrançois Tigeot struct interval_tree_node *it; 515*1cfef1a5SFrançois Tigeot it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1); 516*1cfef1a5SFrançois Tigeot if (it) { 517*1cfef1a5SFrançois Tigeot struct radeon_bo_va *tmp; 518*1cfef1a5SFrançois Tigeot tmp = container_of(it, struct radeon_bo_va, it); 519*1cfef1a5SFrançois Tigeot /* bo and tmp overlap, invalid offset */ 520*1cfef1a5SFrançois Tigeot dev_err(rdev->dev, "bo %p va 0x%010lx conflict with " 521*1cfef1a5SFrançois Tigeot "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo, 522*1cfef1a5SFrançois Tigeot soffset, tmp->bo, tmp->it.start, tmp->it.last); 523*1cfef1a5SFrançois Tigeot mutex_unlock(&vm->mutex); 524*1cfef1a5SFrançois Tigeot return -EINVAL; 525*1cfef1a5SFrançois Tigeot } 526*1cfef1a5SFrançois Tigeot bo_va->it.start = soffset; 527*1cfef1a5SFrançois Tigeot bo_va->it.last = eoffset - 1; 528*1cfef1a5SFrançois Tigeot interval_tree_insert(&bo_va->it, &vm->va); 529*1cfef1a5SFrançois Tigeot } 530*1cfef1a5SFrançois Tigeot 531c6f73aabSFrançois Tigeot bo_va->flags = flags; 532c6f73aabSFrançois Tigeot bo_va->addr = 0; 533c6f73aabSFrançois Tigeot 534*1cfef1a5SFrançois Tigeot soffset >>= radeon_vm_block_size; 535*1cfef1a5SFrançois Tigeot eoffset >>= radeon_vm_block_size; 536c6f73aabSFrançois Tigeot 537c6f73aabSFrançois Tigeot BUG_ON(eoffset >= radeon_vm_num_pdes(rdev)); 538c6f73aabSFrançois Tigeot 539c6f73aabSFrançois Tigeot if (eoffset > vm->max_pde_used) 540c6f73aabSFrançois Tigeot vm->max_pde_used = eoffset; 541c6f73aabSFrançois Tigeot 542c6f73aabSFrançois Tigeot radeon_bo_unreserve(bo_va->bo); 543c6f73aabSFrançois Tigeot 544c6f73aabSFrançois Tigeot /* walk over the address space and allocate the page tables */ 545c6f73aabSFrançois Tigeot for (pt_idx = soffset; pt_idx <= eoffset; ++pt_idx) { 546c6f73aabSFrançois Tigeot struct radeon_bo *pt; 547c6f73aabSFrançois Tigeot 548c6f73aabSFrançois Tigeot if (vm->page_tables[pt_idx].bo) 549c6f73aabSFrançois Tigeot continue; 550c6f73aabSFrançois Tigeot 551c6f73aabSFrançois Tigeot /* drop mutex to allocate and clear page table */ 552*1cfef1a5SFrançois Tigeot mutex_unlock(&vm->mutex); 553c6f73aabSFrançois Tigeot 554c6f73aabSFrançois Tigeot r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8, 555c6f73aabSFrançois Tigeot RADEON_GPU_PAGE_SIZE, true, 556c6f73aabSFrançois Tigeot RADEON_GEM_DOMAIN_VRAM, 0, NULL, &pt); 557c6f73aabSFrançois Tigeot if (r) 558c6f73aabSFrançois Tigeot return r; 559c6f73aabSFrançois Tigeot 560c6f73aabSFrançois Tigeot r = radeon_vm_clear_bo(rdev, pt); 561c6f73aabSFrançois Tigeot if (r) { 562c6f73aabSFrançois Tigeot radeon_bo_unref(&pt); 563ee479021SImre Vadász radeon_bo_reserve(bo_va->bo, false); 564c6f73aabSFrançois Tigeot return r; 565c6f73aabSFrançois Tigeot } 566c6f73aabSFrançois Tigeot 567c6f73aabSFrançois Tigeot /* aquire mutex again */ 568*1cfef1a5SFrançois Tigeot mutex_lock(&vm->mutex); 569c6f73aabSFrançois Tigeot if (vm->page_tables[pt_idx].bo) { 570c6f73aabSFrançois Tigeot /* someone else allocated the pt in the meantime */ 571*1cfef1a5SFrançois Tigeot mutex_unlock(&vm->mutex); 572c6f73aabSFrançois Tigeot radeon_bo_unref(&pt); 573*1cfef1a5SFrançois Tigeot mutex_lock(&vm->mutex); 574c6f73aabSFrançois Tigeot continue; 575c6f73aabSFrançois Tigeot } 576c6f73aabSFrançois Tigeot 577c6f73aabSFrançois Tigeot vm->page_tables[pt_idx].addr = 0; 578c6f73aabSFrançois Tigeot vm->page_tables[pt_idx].bo = pt; 579c6f73aabSFrançois Tigeot } 580c6f73aabSFrançois Tigeot 581*1cfef1a5SFrançois Tigeot mutex_unlock(&vm->mutex); 582ee479021SImre Vadász return radeon_bo_reserve(bo_va->bo, false); 583c6f73aabSFrançois Tigeot } 584c6f73aabSFrançois Tigeot 585c6f73aabSFrançois Tigeot /** 586c6f73aabSFrançois Tigeot * radeon_vm_map_gart - get the physical address of a gart page 587c6f73aabSFrançois Tigeot * 588c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 589c6f73aabSFrançois Tigeot * @addr: the unmapped addr 590c6f73aabSFrançois Tigeot * 591c6f73aabSFrançois Tigeot * Look up the physical address of the page that the pte resolves 592c6f73aabSFrançois Tigeot * to (cayman+). 593c6f73aabSFrançois Tigeot * Returns the physical address of the page. 594c6f73aabSFrançois Tigeot */ 595c6f73aabSFrançois Tigeot uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) 596c6f73aabSFrançois Tigeot { 597c6f73aabSFrançois Tigeot uint64_t result; 598c6f73aabSFrançois Tigeot 599c6f73aabSFrançois Tigeot /* page table offset */ 600ee479021SImre Vadász result = rdev->gart.pages_addr[addr >> PAGE_SHIFT]; 601ee479021SImre Vadász 602ee479021SImre Vadász /* in case cpu page size != gpu page size*/ 603d653c727SFrançois Tigeot result |= addr & (~LINUX_PAGE_MASK); 604c6f73aabSFrançois Tigeot 605c6f73aabSFrançois Tigeot return result; 606c6f73aabSFrançois Tigeot } 607c6f73aabSFrançois Tigeot 608c6f73aabSFrançois Tigeot /** 609c6f73aabSFrançois Tigeot * radeon_vm_page_flags - translate page flags to what the hw uses 610c6f73aabSFrançois Tigeot * 611c6f73aabSFrançois Tigeot * @flags: flags comming from userspace 612c6f73aabSFrançois Tigeot * 613c6f73aabSFrançois Tigeot * Translate the flags the userspace ABI uses to hw flags. 614c6f73aabSFrançois Tigeot */ 615c6f73aabSFrançois Tigeot static uint32_t radeon_vm_page_flags(uint32_t flags) 616c6f73aabSFrançois Tigeot { 617c6f73aabSFrançois Tigeot uint32_t hw_flags = 0; 618c6f73aabSFrançois Tigeot hw_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0; 619c6f73aabSFrançois Tigeot hw_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0; 620c6f73aabSFrançois Tigeot hw_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0; 621c6f73aabSFrançois Tigeot if (flags & RADEON_VM_PAGE_SYSTEM) { 622c6f73aabSFrançois Tigeot hw_flags |= R600_PTE_SYSTEM; 623c6f73aabSFrançois Tigeot hw_flags |= (flags & RADEON_VM_PAGE_SNOOPED) ? R600_PTE_SNOOPED : 0; 624c6f73aabSFrançois Tigeot } 625c6f73aabSFrançois Tigeot return hw_flags; 626c6f73aabSFrançois Tigeot } 627c6f73aabSFrançois Tigeot 628c6f73aabSFrançois Tigeot /** 629c6f73aabSFrançois Tigeot * radeon_vm_update_pdes - make sure that page directory is valid 630c6f73aabSFrançois Tigeot * 631c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 632c6f73aabSFrançois Tigeot * @vm: requested vm 633c6f73aabSFrançois Tigeot * @start: start of GPU address range 634c6f73aabSFrançois Tigeot * @end: end of GPU address range 635c6f73aabSFrançois Tigeot * 636c6f73aabSFrançois Tigeot * Allocates new page tables if necessary 637c6f73aabSFrançois Tigeot * and updates the page directory (cayman+). 638c6f73aabSFrançois Tigeot * Returns 0 for success, error for failure. 639c6f73aabSFrançois Tigeot * 640c6f73aabSFrançois Tigeot * Global and local mutex must be locked! 641c6f73aabSFrançois Tigeot */ 642c6f73aabSFrançois Tigeot int radeon_vm_update_page_directory(struct radeon_device *rdev, 643c6f73aabSFrançois Tigeot struct radeon_vm *vm) 644c6f73aabSFrançois Tigeot { 645c6f73aabSFrançois Tigeot struct radeon_bo *pd = vm->page_directory; 646c6f73aabSFrançois Tigeot uint64_t pd_addr = radeon_bo_gpu_offset(pd); 647c6f73aabSFrançois Tigeot uint32_t incr = RADEON_VM_PTE_COUNT * 8; 648c6f73aabSFrançois Tigeot uint64_t last_pde = ~0, last_pt = ~0; 649c6f73aabSFrançois Tigeot unsigned count = 0, pt_idx, ndw; 650c6f73aabSFrançois Tigeot struct radeon_ib ib; 651c6f73aabSFrançois Tigeot int r; 652c6f73aabSFrançois Tigeot 653c6f73aabSFrançois Tigeot /* padding, etc. */ 654c6f73aabSFrançois Tigeot ndw = 64; 655c6f73aabSFrançois Tigeot 656c6f73aabSFrançois Tigeot /* assume the worst case */ 657c6f73aabSFrançois Tigeot ndw += vm->max_pde_used * 6; 658c6f73aabSFrançois Tigeot 659c6f73aabSFrançois Tigeot /* update too big for an IB */ 660c6f73aabSFrançois Tigeot if (ndw > 0xfffff) 661c6f73aabSFrançois Tigeot return -ENOMEM; 662c6f73aabSFrançois Tigeot 663c6f73aabSFrançois Tigeot r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4); 664c6f73aabSFrançois Tigeot if (r) 665c6f73aabSFrançois Tigeot return r; 666c6f73aabSFrançois Tigeot ib.length_dw = 0; 667c6f73aabSFrançois Tigeot 668c6f73aabSFrançois Tigeot /* walk over the address space and update the page directory */ 669c6f73aabSFrançois Tigeot for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) { 670c6f73aabSFrançois Tigeot struct radeon_bo *bo = vm->page_tables[pt_idx].bo; 671c6f73aabSFrançois Tigeot uint64_t pde, pt; 672c6f73aabSFrançois Tigeot 673c6f73aabSFrançois Tigeot if (bo == NULL) 674c6f73aabSFrançois Tigeot continue; 675c6f73aabSFrançois Tigeot 676c6f73aabSFrançois Tigeot pt = radeon_bo_gpu_offset(bo); 677c6f73aabSFrançois Tigeot if (vm->page_tables[pt_idx].addr == pt) 678c6f73aabSFrançois Tigeot continue; 679c6f73aabSFrançois Tigeot vm->page_tables[pt_idx].addr = pt; 680c6f73aabSFrançois Tigeot 681c6f73aabSFrançois Tigeot pde = pd_addr + pt_idx * 8; 682c6f73aabSFrançois Tigeot if (((last_pde + 8 * count) != pde) || 683c6f73aabSFrançois Tigeot ((last_pt + incr * count) != pt)) { 684c6f73aabSFrançois Tigeot 685c6f73aabSFrançois Tigeot if (count) { 686c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, &ib, last_pde, 687c6f73aabSFrançois Tigeot last_pt, count, incr, 688c6f73aabSFrançois Tigeot R600_PTE_VALID); 689c6f73aabSFrançois Tigeot } 690c6f73aabSFrançois Tigeot 691c6f73aabSFrançois Tigeot count = 1; 692c6f73aabSFrançois Tigeot last_pde = pde; 693c6f73aabSFrançois Tigeot last_pt = pt; 694c6f73aabSFrançois Tigeot } else { 695c6f73aabSFrançois Tigeot ++count; 696c6f73aabSFrançois Tigeot } 697c6f73aabSFrançois Tigeot } 698c6f73aabSFrançois Tigeot 699c6f73aabSFrançois Tigeot if (count) 700c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, &ib, last_pde, last_pt, count, 701c6f73aabSFrançois Tigeot incr, R600_PTE_VALID); 702c6f73aabSFrançois Tigeot 703c6f73aabSFrançois Tigeot if (ib.length_dw != 0) { 704c6f73aabSFrançois Tigeot radeon_asic_vm_pad_ib(rdev, &ib); 705*1cfef1a5SFrançois Tigeot 706*1cfef1a5SFrançois Tigeot radeon_semaphore_sync_resv(rdev, ib.semaphore, pd->tbo.resv, false); 707*1cfef1a5SFrançois Tigeot radeon_semaphore_sync_fence(ib.semaphore, vm->last_id_use); 708c6f73aabSFrançois Tigeot WARN_ON(ib.length_dw > ndw); 709c6f73aabSFrançois Tigeot r = radeon_ib_schedule(rdev, &ib, NULL, false); 710c6f73aabSFrançois Tigeot if (r) { 711c6f73aabSFrançois Tigeot radeon_ib_free(rdev, &ib); 712c6f73aabSFrançois Tigeot return r; 713c6f73aabSFrançois Tigeot } 714c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->fence); 715c6f73aabSFrançois Tigeot vm->fence = radeon_fence_ref(ib.fence); 716c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->last_flush); 717c6f73aabSFrançois Tigeot } 718c6f73aabSFrançois Tigeot radeon_ib_free(rdev, &ib); 719c6f73aabSFrançois Tigeot 720c6f73aabSFrançois Tigeot return 0; 721c6f73aabSFrançois Tigeot } 722c6f73aabSFrançois Tigeot 723c6f73aabSFrançois Tigeot /** 724c6f73aabSFrançois Tigeot * radeon_vm_frag_ptes - add fragment information to PTEs 725c6f73aabSFrançois Tigeot * 726c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 727c6f73aabSFrançois Tigeot * @ib: IB for the update 728c6f73aabSFrançois Tigeot * @pe_start: first PTE to handle 729c6f73aabSFrançois Tigeot * @pe_end: last PTE to handle 730c6f73aabSFrançois Tigeot * @addr: addr those PTEs should point to 731c6f73aabSFrançois Tigeot * @flags: hw mapping flags 732c6f73aabSFrançois Tigeot * 733c6f73aabSFrançois Tigeot * Global and local mutex must be locked! 734c6f73aabSFrançois Tigeot */ 735c6f73aabSFrançois Tigeot static void radeon_vm_frag_ptes(struct radeon_device *rdev, 736c6f73aabSFrançois Tigeot struct radeon_ib *ib, 737c6f73aabSFrançois Tigeot uint64_t pe_start, uint64_t pe_end, 738c6f73aabSFrançois Tigeot uint64_t addr, uint32_t flags) 739c6f73aabSFrançois Tigeot { 740c6f73aabSFrançois Tigeot /** 741c6f73aabSFrançois Tigeot * The MC L1 TLB supports variable sized pages, based on a fragment 742c6f73aabSFrançois Tigeot * field in the PTE. When this field is set to a non-zero value, page 743c6f73aabSFrançois Tigeot * granularity is increased from 4KB to (1 << (12 + frag)). The PTE 744c6f73aabSFrançois Tigeot * flags are considered valid for all PTEs within the fragment range 745c6f73aabSFrançois Tigeot * and corresponding mappings are assumed to be physically contiguous. 746c6f73aabSFrançois Tigeot * 747c6f73aabSFrançois Tigeot * The L1 TLB can store a single PTE for the whole fragment, 748c6f73aabSFrançois Tigeot * significantly increasing the space available for translation 749c6f73aabSFrançois Tigeot * caching. This leads to large improvements in throughput when the 750c6f73aabSFrançois Tigeot * TLB is under pressure. 751c6f73aabSFrançois Tigeot * 752c6f73aabSFrançois Tigeot * The L2 TLB distributes small and large fragments into two 753c6f73aabSFrançois Tigeot * asymmetric partitions. The large fragment cache is significantly 754c6f73aabSFrançois Tigeot * larger. Thus, we try to use large fragments wherever possible. 755c6f73aabSFrançois Tigeot * Userspace can support this by aligning virtual base address and 756c6f73aabSFrançois Tigeot * allocation size to the fragment size. 757c6f73aabSFrançois Tigeot */ 758c6f73aabSFrançois Tigeot 759c6f73aabSFrançois Tigeot /* NI is optimized for 256KB fragments, SI and newer for 64KB */ 760ee479021SImre Vadász uint64_t frag_flags = rdev->family == CHIP_CAYMAN ? 761c6f73aabSFrançois Tigeot R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB; 762ee479021SImre Vadász uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80; 763c6f73aabSFrançois Tigeot 764c6f73aabSFrançois Tigeot uint64_t frag_start = ALIGN(pe_start, frag_align); 765c6f73aabSFrançois Tigeot uint64_t frag_end = pe_end & ~(frag_align - 1); 766c6f73aabSFrançois Tigeot 767c6f73aabSFrançois Tigeot unsigned count; 768c6f73aabSFrançois Tigeot 769c6f73aabSFrançois Tigeot /* system pages are non continuously */ 770c6f73aabSFrançois Tigeot if ((flags & R600_PTE_SYSTEM) || !(flags & R600_PTE_VALID) || 771c6f73aabSFrançois Tigeot (frag_start >= frag_end)) { 772c6f73aabSFrançois Tigeot 773c6f73aabSFrançois Tigeot count = (pe_end - pe_start) / 8; 774c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, ib, pe_start, addr, count, 775c6f73aabSFrançois Tigeot RADEON_GPU_PAGE_SIZE, flags); 776c6f73aabSFrançois Tigeot return; 777c6f73aabSFrançois Tigeot } 778c6f73aabSFrançois Tigeot 779c6f73aabSFrançois Tigeot /* handle the 4K area at the beginning */ 780c6f73aabSFrançois Tigeot if (pe_start != frag_start) { 781c6f73aabSFrançois Tigeot count = (frag_start - pe_start) / 8; 782c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, ib, pe_start, addr, count, 783c6f73aabSFrançois Tigeot RADEON_GPU_PAGE_SIZE, flags); 784c6f73aabSFrançois Tigeot addr += RADEON_GPU_PAGE_SIZE * count; 785c6f73aabSFrançois Tigeot } 786c6f73aabSFrançois Tigeot 787c6f73aabSFrançois Tigeot /* handle the area in the middle */ 788c6f73aabSFrançois Tigeot count = (frag_end - frag_start) / 8; 789c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, ib, frag_start, addr, count, 790c6f73aabSFrançois Tigeot RADEON_GPU_PAGE_SIZE, flags | frag_flags); 791c6f73aabSFrançois Tigeot 792c6f73aabSFrançois Tigeot /* handle the 4K area at the end */ 793c6f73aabSFrançois Tigeot if (frag_end != pe_end) { 794c6f73aabSFrançois Tigeot addr += RADEON_GPU_PAGE_SIZE * count; 795c6f73aabSFrançois Tigeot count = (pe_end - frag_end) / 8; 796c6f73aabSFrançois Tigeot radeon_vm_set_pages(rdev, ib, frag_end, addr, count, 797c6f73aabSFrançois Tigeot RADEON_GPU_PAGE_SIZE, flags); 798c6f73aabSFrançois Tigeot } 799c6f73aabSFrançois Tigeot } 800c6f73aabSFrançois Tigeot 801c6f73aabSFrançois Tigeot /** 802c6f73aabSFrançois Tigeot * radeon_vm_update_ptes - make sure that page tables are valid 803c6f73aabSFrançois Tigeot * 804c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 805c6f73aabSFrançois Tigeot * @vm: requested vm 806c6f73aabSFrançois Tigeot * @start: start of GPU address range 807c6f73aabSFrançois Tigeot * @end: end of GPU address range 808c6f73aabSFrançois Tigeot * @dst: destination address to map to 809c6f73aabSFrançois Tigeot * @flags: mapping flags 810c6f73aabSFrançois Tigeot * 811c6f73aabSFrançois Tigeot * Update the page tables in the range @start - @end (cayman+). 812c6f73aabSFrançois Tigeot * 813c6f73aabSFrançois Tigeot * Global and local mutex must be locked! 814c6f73aabSFrançois Tigeot */ 815c6f73aabSFrançois Tigeot static void radeon_vm_update_ptes(struct radeon_device *rdev, 816c6f73aabSFrançois Tigeot struct radeon_vm *vm, 817c6f73aabSFrançois Tigeot struct radeon_ib *ib, 818c6f73aabSFrançois Tigeot uint64_t start, uint64_t end, 819c6f73aabSFrançois Tigeot uint64_t dst, uint32_t flags) 820c6f73aabSFrançois Tigeot { 821c6f73aabSFrançois Tigeot uint64_t mask = RADEON_VM_PTE_COUNT - 1; 822c6f73aabSFrançois Tigeot uint64_t last_pte = ~0, last_dst = ~0; 823c6f73aabSFrançois Tigeot unsigned count = 0; 824c6f73aabSFrançois Tigeot uint64_t addr; 825c6f73aabSFrançois Tigeot 826c6f73aabSFrançois Tigeot /* walk over the address space and update the page tables */ 827c6f73aabSFrançois Tigeot for (addr = start; addr < end; ) { 828c6f73aabSFrançois Tigeot uint64_t pt_idx = addr >> radeon_vm_block_size; 829c6f73aabSFrançois Tigeot struct radeon_bo *pt = vm->page_tables[pt_idx].bo; 830c6f73aabSFrançois Tigeot unsigned nptes; 831c6f73aabSFrançois Tigeot uint64_t pte; 832c6f73aabSFrançois Tigeot 833*1cfef1a5SFrançois Tigeot radeon_semaphore_sync_resv(rdev, ib->semaphore, pt->tbo.resv, false); 834c6f73aabSFrançois Tigeot 835c6f73aabSFrançois Tigeot if ((addr & ~mask) == (end & ~mask)) 836c6f73aabSFrançois Tigeot nptes = end - addr; 837c6f73aabSFrançois Tigeot else 838c6f73aabSFrançois Tigeot nptes = RADEON_VM_PTE_COUNT - (addr & mask); 839c6f73aabSFrançois Tigeot 840c6f73aabSFrançois Tigeot pte = radeon_bo_gpu_offset(pt); 841c6f73aabSFrançois Tigeot pte += (addr & mask) * 8; 842c6f73aabSFrançois Tigeot 843c6f73aabSFrançois Tigeot if ((last_pte + 8 * count) != pte) { 844c6f73aabSFrançois Tigeot 845c6f73aabSFrançois Tigeot if (count) { 846c6f73aabSFrançois Tigeot radeon_vm_frag_ptes(rdev, ib, last_pte, 847c6f73aabSFrançois Tigeot last_pte + 8 * count, 848c6f73aabSFrançois Tigeot last_dst, flags); 849c6f73aabSFrançois Tigeot } 850c6f73aabSFrançois Tigeot 851c6f73aabSFrançois Tigeot count = nptes; 852c6f73aabSFrançois Tigeot last_pte = pte; 853c6f73aabSFrançois Tigeot last_dst = dst; 854c6f73aabSFrançois Tigeot } else { 855c6f73aabSFrançois Tigeot count += nptes; 856c6f73aabSFrançois Tigeot } 857c6f73aabSFrançois Tigeot 858c6f73aabSFrançois Tigeot addr += nptes; 859c6f73aabSFrançois Tigeot dst += nptes * RADEON_GPU_PAGE_SIZE; 860c6f73aabSFrançois Tigeot } 861c6f73aabSFrançois Tigeot 862c6f73aabSFrançois Tigeot if (count) { 863c6f73aabSFrançois Tigeot radeon_vm_frag_ptes(rdev, ib, last_pte, 864c6f73aabSFrançois Tigeot last_pte + 8 * count, 865c6f73aabSFrançois Tigeot last_dst, flags); 866c6f73aabSFrançois Tigeot } 867c6f73aabSFrançois Tigeot } 868c6f73aabSFrançois Tigeot 869c6f73aabSFrançois Tigeot /** 870c6f73aabSFrançois Tigeot * radeon_vm_bo_update - map a bo into the vm page table 871c6f73aabSFrançois Tigeot * 872c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 873c6f73aabSFrançois Tigeot * @vm: requested vm 874c6f73aabSFrançois Tigeot * @bo: radeon buffer object 875c6f73aabSFrançois Tigeot * @mem: ttm mem 876c6f73aabSFrançois Tigeot * 877c6f73aabSFrançois Tigeot * Fill in the page table entries for @bo (cayman+). 878c6f73aabSFrançois Tigeot * Returns 0 for success, -EINVAL for failure. 879c6f73aabSFrançois Tigeot * 880c6f73aabSFrançois Tigeot * Object have to be reserved and mutex must be locked! 881c6f73aabSFrançois Tigeot */ 882c6f73aabSFrançois Tigeot int radeon_vm_bo_update(struct radeon_device *rdev, 883c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va, 884c6f73aabSFrançois Tigeot struct ttm_mem_reg *mem) 885c6f73aabSFrançois Tigeot { 886c6f73aabSFrançois Tigeot struct radeon_vm *vm = bo_va->vm; 887c6f73aabSFrançois Tigeot struct radeon_ib ib; 888*1cfef1a5SFrançois Tigeot unsigned nptes, ndw; 889c6f73aabSFrançois Tigeot uint64_t addr; 890c6f73aabSFrançois Tigeot int r; 891c6f73aabSFrançois Tigeot 892*1cfef1a5SFrançois Tigeot if (!bo_va->it.start) { 893c6f73aabSFrançois Tigeot dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n", 894c6f73aabSFrançois Tigeot bo_va->bo, vm); 895c6f73aabSFrançois Tigeot return -EINVAL; 896c6f73aabSFrançois Tigeot } 897c6f73aabSFrançois Tigeot 898c6f73aabSFrançois Tigeot list_del_init(&bo_va->vm_status); 899c6f73aabSFrançois Tigeot 900c6f73aabSFrançois Tigeot bo_va->flags &= ~RADEON_VM_PAGE_VALID; 901c6f73aabSFrançois Tigeot bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM; 902c6f73aabSFrançois Tigeot bo_va->flags &= ~RADEON_VM_PAGE_SNOOPED; 903c6f73aabSFrançois Tigeot if (mem) { 904c6f73aabSFrançois Tigeot addr = mem->start << PAGE_SHIFT; 905c6f73aabSFrançois Tigeot if (mem->mem_type != TTM_PL_SYSTEM) { 906c6f73aabSFrançois Tigeot bo_va->flags |= RADEON_VM_PAGE_VALID; 907c6f73aabSFrançois Tigeot } 908c6f73aabSFrançois Tigeot if (mem->mem_type == TTM_PL_TT) { 909c6f73aabSFrançois Tigeot bo_va->flags |= RADEON_VM_PAGE_SYSTEM; 910c6f73aabSFrançois Tigeot if (!(bo_va->bo->flags & (RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC))) 911c6f73aabSFrançois Tigeot bo_va->flags |= RADEON_VM_PAGE_SNOOPED; 912c6f73aabSFrançois Tigeot 913c6f73aabSFrançois Tigeot } else { 914c6f73aabSFrançois Tigeot addr += rdev->vm_manager.vram_base_offset; 915c6f73aabSFrançois Tigeot } 916c6f73aabSFrançois Tigeot } else { 917c6f73aabSFrançois Tigeot addr = 0; 918c6f73aabSFrançois Tigeot } 919c6f73aabSFrançois Tigeot 920c6f73aabSFrançois Tigeot if (addr == bo_va->addr) 921c6f73aabSFrançois Tigeot return 0; 922c6f73aabSFrançois Tigeot bo_va->addr = addr; 923c6f73aabSFrançois Tigeot 924c6f73aabSFrançois Tigeot #ifdef TRACE_TODO 925c6f73aabSFrançois Tigeot trace_radeon_vm_bo_update(bo_va); 926c6f73aabSFrançois Tigeot #endif 927c6f73aabSFrançois Tigeot 928*1cfef1a5SFrançois Tigeot nptes = bo_va->it.last - bo_va->it.start + 1; 929c6f73aabSFrançois Tigeot 930c6f73aabSFrançois Tigeot /* padding, etc. */ 931c6f73aabSFrançois Tigeot ndw = 64; 932c6f73aabSFrançois Tigeot 933*1cfef1a5SFrançois Tigeot if (radeon_vm_block_size > 11) 934*1cfef1a5SFrançois Tigeot /* reserve space for one header for every 2k dwords */ 935*1cfef1a5SFrançois Tigeot ndw += (nptes >> 11) * 4; 936*1cfef1a5SFrançois Tigeot else 937*1cfef1a5SFrançois Tigeot /* reserve space for one header for 938*1cfef1a5SFrançois Tigeot every (1 << BLOCK_SIZE) entries */ 939*1cfef1a5SFrançois Tigeot ndw += (nptes >> radeon_vm_block_size) * 4; 940c6f73aabSFrançois Tigeot 941*1cfef1a5SFrançois Tigeot /* reserve space for pte addresses */ 942c6f73aabSFrançois Tigeot ndw += nptes * 2; 943c6f73aabSFrançois Tigeot 944c6f73aabSFrançois Tigeot /* update too big for an IB */ 945c6f73aabSFrançois Tigeot if (ndw > 0xfffff) 946c6f73aabSFrançois Tigeot return -ENOMEM; 947c6f73aabSFrançois Tigeot 948c6f73aabSFrançois Tigeot r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4); 949c6f73aabSFrançois Tigeot if (r) 950c6f73aabSFrançois Tigeot return r; 951c6f73aabSFrançois Tigeot ib.length_dw = 0; 952c6f73aabSFrançois Tigeot 953*1cfef1a5SFrançois Tigeot radeon_vm_update_ptes(rdev, vm, &ib, bo_va->it.start, 954*1cfef1a5SFrançois Tigeot bo_va->it.last + 1, addr, 955*1cfef1a5SFrançois Tigeot radeon_vm_page_flags(bo_va->flags)); 956c6f73aabSFrançois Tigeot 957*1cfef1a5SFrançois Tigeot radeon_semaphore_sync_fence(ib.semaphore, vm->fence); 958c6f73aabSFrançois Tigeot r = radeon_ib_schedule(rdev, &ib, NULL, false); 959c6f73aabSFrançois Tigeot if (r) { 960c6f73aabSFrançois Tigeot radeon_ib_free(rdev, &ib); 961c6f73aabSFrançois Tigeot return r; 962c6f73aabSFrançois Tigeot } 963c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->fence); 964c6f73aabSFrançois Tigeot vm->fence = radeon_fence_ref(ib.fence); 965c6f73aabSFrançois Tigeot radeon_ib_free(rdev, &ib); 966c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->last_flush); 967c6f73aabSFrançois Tigeot 968c6f73aabSFrançois Tigeot return 0; 969c6f73aabSFrançois Tigeot } 970c6f73aabSFrançois Tigeot 971c6f73aabSFrançois Tigeot /** 972c6f73aabSFrançois Tigeot * radeon_vm_clear_freed - clear freed BOs in the PT 973c6f73aabSFrançois Tigeot * 974c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 975c6f73aabSFrançois Tigeot * @vm: requested vm 976c6f73aabSFrançois Tigeot * 977c6f73aabSFrançois Tigeot * Make sure all freed BOs are cleared in the PT. 978c6f73aabSFrançois Tigeot * Returns 0 for success. 979c6f73aabSFrançois Tigeot * 980c6f73aabSFrançois Tigeot * PTs have to be reserved and mutex must be locked! 981c6f73aabSFrançois Tigeot */ 982c6f73aabSFrançois Tigeot int radeon_vm_clear_freed(struct radeon_device *rdev, 983c6f73aabSFrançois Tigeot struct radeon_vm *vm) 984c6f73aabSFrançois Tigeot { 985ee479021SImre Vadász struct radeon_bo_va *bo_va, *tmp; 986c6f73aabSFrançois Tigeot int r; 987c6f73aabSFrançois Tigeot 988ee479021SImre Vadász list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) { 989c6f73aabSFrançois Tigeot r = radeon_vm_bo_update(rdev, bo_va, NULL); 990c6f73aabSFrançois Tigeot kfree(bo_va); 991c6f73aabSFrançois Tigeot if (r) 992c6f73aabSFrançois Tigeot return r; 993c6f73aabSFrançois Tigeot } 994c6f73aabSFrançois Tigeot return 0; 995c6f73aabSFrançois Tigeot 996c6f73aabSFrançois Tigeot } 997c6f73aabSFrançois Tigeot 998c6f73aabSFrançois Tigeot /** 999c6f73aabSFrançois Tigeot * radeon_vm_clear_invalids - clear invalidated BOs in the PT 1000c6f73aabSFrançois Tigeot * 1001c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 1002c6f73aabSFrançois Tigeot * @vm: requested vm 1003c6f73aabSFrançois Tigeot * 1004c6f73aabSFrançois Tigeot * Make sure all invalidated BOs are cleared in the PT. 1005c6f73aabSFrançois Tigeot * Returns 0 for success. 1006c6f73aabSFrançois Tigeot * 1007c6f73aabSFrançois Tigeot * PTs have to be reserved and mutex must be locked! 1008c6f73aabSFrançois Tigeot */ 1009c6f73aabSFrançois Tigeot int radeon_vm_clear_invalids(struct radeon_device *rdev, 1010c6f73aabSFrançois Tigeot struct radeon_vm *vm) 1011c6f73aabSFrançois Tigeot { 1012ee479021SImre Vadász struct radeon_bo_va *bo_va, *tmp; 1013c6f73aabSFrançois Tigeot int r; 1014c6f73aabSFrançois Tigeot 1015ee479021SImre Vadász list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, vm_status) { 1016c6f73aabSFrançois Tigeot r = radeon_vm_bo_update(rdev, bo_va, NULL); 1017c6f73aabSFrançois Tigeot if (r) 1018c6f73aabSFrançois Tigeot return r; 1019c6f73aabSFrançois Tigeot } 1020c6f73aabSFrançois Tigeot return 0; 1021c6f73aabSFrançois Tigeot } 1022c6f73aabSFrançois Tigeot 1023c6f73aabSFrançois Tigeot /** 1024c6f73aabSFrançois Tigeot * radeon_vm_bo_rmv - remove a bo to a specific vm 1025c6f73aabSFrançois Tigeot * 1026c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 1027c6f73aabSFrançois Tigeot * @bo_va: requested bo_va 1028c6f73aabSFrançois Tigeot * 1029c6f73aabSFrançois Tigeot * Remove @bo_va->bo from the requested vm (cayman+). 1030c6f73aabSFrançois Tigeot * 1031c6f73aabSFrançois Tigeot * Object have to be reserved! 1032c6f73aabSFrançois Tigeot */ 1033c6f73aabSFrançois Tigeot void radeon_vm_bo_rmv(struct radeon_device *rdev, 1034c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va) 1035c6f73aabSFrançois Tigeot { 1036c6f73aabSFrançois Tigeot struct radeon_vm *vm = bo_va->vm; 1037c6f73aabSFrançois Tigeot 1038c6f73aabSFrançois Tigeot list_del(&bo_va->bo_list); 1039c6f73aabSFrançois Tigeot 1040*1cfef1a5SFrançois Tigeot mutex_lock(&vm->mutex); 1041*1cfef1a5SFrançois Tigeot interval_tree_remove(&bo_va->it, &vm->va); 1042c6f73aabSFrançois Tigeot list_del(&bo_va->vm_status); 1043c6f73aabSFrançois Tigeot 1044c6f73aabSFrançois Tigeot if (bo_va->addr) { 1045ee479021SImre Vadász bo_va->bo = NULL; 1046c6f73aabSFrançois Tigeot list_add(&bo_va->vm_status, &vm->freed); 1047c6f73aabSFrançois Tigeot } else { 1048c6f73aabSFrançois Tigeot kfree(bo_va); 1049c6f73aabSFrançois Tigeot } 1050c6f73aabSFrançois Tigeot 1051*1cfef1a5SFrançois Tigeot mutex_unlock(&vm->mutex); 1052c6f73aabSFrançois Tigeot } 1053c6f73aabSFrançois Tigeot 1054c6f73aabSFrançois Tigeot /** 1055c6f73aabSFrançois Tigeot * radeon_vm_bo_invalidate - mark the bo as invalid 1056c6f73aabSFrançois Tigeot * 1057c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 1058c6f73aabSFrançois Tigeot * @vm: requested vm 1059c6f73aabSFrançois Tigeot * @bo: radeon buffer object 1060c6f73aabSFrançois Tigeot * 1061c6f73aabSFrançois Tigeot * Mark @bo as invalid (cayman+). 1062c6f73aabSFrançois Tigeot */ 1063c6f73aabSFrançois Tigeot void radeon_vm_bo_invalidate(struct radeon_device *rdev, 1064c6f73aabSFrançois Tigeot struct radeon_bo *bo) 1065c6f73aabSFrançois Tigeot { 1066c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va; 1067c6f73aabSFrançois Tigeot 1068c6f73aabSFrançois Tigeot list_for_each_entry(bo_va, &bo->va, bo_list) { 1069c6f73aabSFrançois Tigeot if (bo_va->addr) { 1070ee479021SImre Vadász mutex_lock(&bo_va->vm->mutex); 1071c6f73aabSFrançois Tigeot list_del(&bo_va->vm_status); 1072c6f73aabSFrançois Tigeot list_add(&bo_va->vm_status, &bo_va->vm->invalidated); 1073ee479021SImre Vadász mutex_unlock(&bo_va->vm->mutex); 1074c6f73aabSFrançois Tigeot } 1075c6f73aabSFrançois Tigeot } 1076c6f73aabSFrançois Tigeot } 1077c6f73aabSFrançois Tigeot 1078c6f73aabSFrançois Tigeot /** 1079c6f73aabSFrançois Tigeot * radeon_vm_init - initialize a vm instance 1080c6f73aabSFrançois Tigeot * 1081c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 1082c6f73aabSFrançois Tigeot * @vm: requested vm 1083c6f73aabSFrançois Tigeot * 1084c6f73aabSFrançois Tigeot * Init @vm fields (cayman+). 1085c6f73aabSFrançois Tigeot */ 1086c6f73aabSFrançois Tigeot int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm) 1087c6f73aabSFrançois Tigeot { 1088c6f73aabSFrançois Tigeot const unsigned align = min(RADEON_VM_PTB_ALIGN_SIZE, 1089c6f73aabSFrançois Tigeot RADEON_VM_PTE_COUNT * 8); 1090c6f73aabSFrançois Tigeot unsigned pd_size, pd_entries, pts_size; 1091c6f73aabSFrançois Tigeot int r; 1092c6f73aabSFrançois Tigeot 1093c6f73aabSFrançois Tigeot vm->id = 0; 1094c6f73aabSFrançois Tigeot vm->ib_bo_va = NULL; 1095c6f73aabSFrançois Tigeot vm->fence = NULL; 1096c6f73aabSFrançois Tigeot vm->last_flush = NULL; 1097c6f73aabSFrançois Tigeot vm->last_id_use = NULL; 1098c6f73aabSFrançois Tigeot lockinit(&vm->mutex, "rvmmtx", 0, LK_CANRECURSE); 1099*1cfef1a5SFrançois Tigeot vm->va = LINUX_RB_ROOT; 1100c6f73aabSFrançois Tigeot INIT_LIST_HEAD(&vm->invalidated); 1101c6f73aabSFrançois Tigeot INIT_LIST_HEAD(&vm->freed); 1102c6f73aabSFrançois Tigeot 1103c6f73aabSFrançois Tigeot pd_size = radeon_vm_directory_size(rdev); 1104c6f73aabSFrançois Tigeot pd_entries = radeon_vm_num_pdes(rdev); 1105c6f73aabSFrançois Tigeot 1106c6f73aabSFrançois Tigeot /* allocate page table array */ 1107c6f73aabSFrançois Tigeot pts_size = pd_entries * sizeof(struct radeon_vm_pt); 1108c6f73aabSFrançois Tigeot vm->page_tables = kzalloc(pts_size, GFP_KERNEL); 1109c6f73aabSFrançois Tigeot if (vm->page_tables == NULL) { 1110c6f73aabSFrançois Tigeot DRM_ERROR("Cannot allocate memory for page table array\n"); 1111c6f73aabSFrançois Tigeot return -ENOMEM; 1112c6f73aabSFrançois Tigeot } 1113c6f73aabSFrançois Tigeot 1114c6f73aabSFrançois Tigeot r = radeon_bo_create(rdev, pd_size, align, true, 1115c6f73aabSFrançois Tigeot RADEON_GEM_DOMAIN_VRAM, 0, NULL, 1116c6f73aabSFrançois Tigeot &vm->page_directory); 1117c6f73aabSFrançois Tigeot if (r) 1118c6f73aabSFrançois Tigeot return r; 1119c6f73aabSFrançois Tigeot 1120c6f73aabSFrançois Tigeot r = radeon_vm_clear_bo(rdev, vm->page_directory); 1121c6f73aabSFrançois Tigeot if (r) { 1122c6f73aabSFrançois Tigeot radeon_bo_unref(&vm->page_directory); 1123c6f73aabSFrançois Tigeot vm->page_directory = NULL; 1124c6f73aabSFrançois Tigeot return r; 1125c6f73aabSFrançois Tigeot } 1126c6f73aabSFrançois Tigeot 1127c6f73aabSFrançois Tigeot return 0; 1128c6f73aabSFrançois Tigeot } 1129c6f73aabSFrançois Tigeot 1130c6f73aabSFrançois Tigeot /** 1131c6f73aabSFrançois Tigeot * radeon_vm_fini - tear down a vm instance 1132c6f73aabSFrançois Tigeot * 1133c6f73aabSFrançois Tigeot * @rdev: radeon_device pointer 1134c6f73aabSFrançois Tigeot * @vm: requested vm 1135c6f73aabSFrançois Tigeot * 1136c6f73aabSFrançois Tigeot * Tear down @vm (cayman+). 1137c6f73aabSFrançois Tigeot * Unbind the VM and remove all bos from the vm bo list 1138c6f73aabSFrançois Tigeot */ 1139c6f73aabSFrançois Tigeot void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm) 1140c6f73aabSFrançois Tigeot { 1141c6f73aabSFrançois Tigeot struct radeon_bo_va *bo_va, *tmp; 1142c6f73aabSFrançois Tigeot int i, r; 1143c6f73aabSFrançois Tigeot 1144*1cfef1a5SFrançois Tigeot if (!RB_EMPTY_ROOT(&vm->va)) { 1145c6f73aabSFrançois Tigeot dev_err(rdev->dev, "still active bo inside vm\n"); 1146c6f73aabSFrançois Tigeot } 1147*1cfef1a5SFrançois Tigeot #ifndef __DragonFly__ 1148*1cfef1a5SFrançois Tigeot rbtree_postorder_for_each_entry_safe(bo_va, tmp, &vm->va, it.rb) { 1149*1cfef1a5SFrançois Tigeot #else 1150*1cfef1a5SFrançois Tigeot /* 1151*1cfef1a5SFrançois Tigeot * DFly interval tree mock-up does not use RB trees, the RB iterator 1152*1cfef1a5SFrançois Tigeot * may not be used. 1153*1cfef1a5SFrançois Tigeot * 1154*1cfef1a5SFrançois Tigeot * rbtree_postorder_for_each_entry_safe(bo_va, tmp, &vm->va, it.rb) 1155*1cfef1a5SFrançois Tigeot * 1156*1cfef1a5SFrançois Tigeot * This code is removing all entries so it is fairly easy to replace. 1157*1cfef1a5SFrançois Tigeot */ 1158*1cfef1a5SFrançois Tigeot while (vm->va.rb_node) { 1159*1cfef1a5SFrançois Tigeot bo_va = container_of((void *)vm->va.rb_node, struct radeon_bo_va, it); 1160*1cfef1a5SFrançois Tigeot #endif 1161*1cfef1a5SFrançois Tigeot interval_tree_remove(&bo_va->it, &vm->va); 1162c6f73aabSFrançois Tigeot r = radeon_bo_reserve(bo_va->bo, false); 1163c6f73aabSFrançois Tigeot if (!r) { 1164c6f73aabSFrançois Tigeot list_del_init(&bo_va->bo_list); 1165c6f73aabSFrançois Tigeot radeon_bo_unreserve(bo_va->bo); 1166c6f73aabSFrançois Tigeot kfree(bo_va); 1167c6f73aabSFrançois Tigeot } 1168c6f73aabSFrançois Tigeot } 1169ee479021SImre Vadász list_for_each_entry_safe(bo_va, tmp, &vm->freed, vm_status) 1170c6f73aabSFrançois Tigeot kfree(bo_va); 1171c6f73aabSFrançois Tigeot 1172c6f73aabSFrançois Tigeot for (i = 0; i < radeon_vm_num_pdes(rdev); i++) 1173c6f73aabSFrançois Tigeot radeon_bo_unref(&vm->page_tables[i].bo); 1174c6f73aabSFrançois Tigeot kfree(vm->page_tables); 1175c6f73aabSFrançois Tigeot 1176c6f73aabSFrançois Tigeot radeon_bo_unref(&vm->page_directory); 1177c6f73aabSFrançois Tigeot 1178c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->fence); 1179c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->last_flush); 1180c6f73aabSFrançois Tigeot radeon_fence_unref(&vm->last_id_use); 1181c6f73aabSFrançois Tigeot 1182c6f73aabSFrançois Tigeot lockuninit(&vm->mutex); 1183c6f73aabSFrançois Tigeot } 1184