+/**
+ * amdgpu_vm_alloc_pts - Allocate page tables.
+ *
+ * @adev: amdgpu_device pointer
+ * @vm: VM to allocate page tables for
+ * @saddr: Start address which needs to be allocated
+ * @size: Size from start address we need.
+ *
+ * Make sure the page tables are allocated.
+ */
+int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ uint64_t saddr, uint64_t size)
+{
+ unsigned last_pfn, pt_idx;
+ uint64_t eaddr;
+ int r;
+
+ /* validate the parameters */
+ if (saddr & AMDGPU_GPU_PAGE_MASK || size & AMDGPU_GPU_PAGE_MASK)
+ return -EINVAL;
+
+ eaddr = saddr + size - 1;
+ last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE;
+ if (last_pfn >= adev->vm_manager.max_pfn) {
+ dev_err(adev->dev, "va above limit (0x%08X >= 0x%08X)\n",
+ last_pfn, adev->vm_manager.max_pfn);
+ return -EINVAL;
+ }
+
+ saddr /= AMDGPU_GPU_PAGE_SIZE;
+ eaddr /= AMDGPU_GPU_PAGE_SIZE;
+
+ saddr >>= amdgpu_vm_block_size;
+ eaddr >>= amdgpu_vm_block_size;
+
+ BUG_ON(eaddr >= amdgpu_vm_num_pdes(adev));
+
+ if (eaddr > vm->max_pde_used)
+ vm->max_pde_used = eaddr;
+
+ /* walk over the address space and allocate the page tables */
+ for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
+ struct reservation_object *resv = vm->page_directory->tbo.resv;
+ struct amdgpu_bo *pt;
+
+ if (vm->page_tables[pt_idx].bo)
+ continue;
+
+ r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
+ AMDGPU_GPU_PAGE_SIZE, true,
+ AMDGPU_GEM_DOMAIN_VRAM,
+ AMDGPU_GEM_CREATE_NO_CPU_ACCESS |
+ AMDGPU_GEM_CREATE_SHADOW |
+ AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
+ AMDGPU_GEM_CREATE_VRAM_CLEARED,
+ NULL, resv, &pt);
+ if (r)
+ return r;
+
+ /* Keep a reference to the page table to avoid freeing
+ * them up in the wrong order.
+ */
+ pt->parent = amdgpu_bo_ref(vm->page_directory);
+
+ vm->page_tables[pt_idx].bo = pt;
+ vm->page_tables[pt_idx].addr = 0;
+ }
+
+ return 0;
+}
+