Merge tag 'v4.4.6' into linux-linaro-lsk-v4.4
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_vm.c
index ae037e5b6ad016d6ee70545b814d082da84f22c3..8c5ec151ddac9565b961c5c464e6eee211838604 100644 (file)
@@ -885,17 +885,21 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
        struct amdgpu_bo_va_mapping *mapping;
        int r;
 
+       spin_lock(&vm->freed_lock);
        while (!list_empty(&vm->freed)) {
                mapping = list_first_entry(&vm->freed,
                        struct amdgpu_bo_va_mapping, list);
                list_del(&mapping->list);
-
+               spin_unlock(&vm->freed_lock);
                r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, 0, 0, NULL);
                kfree(mapping);
                if (r)
                        return r;
 
+               spin_lock(&vm->freed_lock);
        }
+       spin_unlock(&vm->freed_lock);
+
        return 0;
 
 }
@@ -1006,13 +1010,13 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                return -EINVAL;
 
        /* make sure object fit at this offset */
-       eaddr = saddr + size;
+       eaddr = saddr + size - 1;
        if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo)))
                return -EINVAL;
 
        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",
+       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;
        }
@@ -1021,7 +1025,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
        eaddr /= AMDGPU_GPU_PAGE_SIZE;
 
        spin_lock(&vm->it_lock);
-       it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
+       it = interval_tree_iter_first(&vm->va, saddr, eaddr);
        spin_unlock(&vm->it_lock);
        if (it) {
                struct amdgpu_bo_va_mapping *tmp;
@@ -1042,7 +1046,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
 
        INIT_LIST_HEAD(&mapping->list);
        mapping->it.start = saddr;
-       mapping->it.last = eaddr - 1;
+       mapping->it.last = eaddr;
        mapping->offset = offset;
        mapping->flags = flags;
 
@@ -1079,6 +1083,11 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
                if (r)
                        goto error_free;
 
+               /* Keep a reference to the page table to avoid freeing
+                * them up in the wrong order.
+                */
+               pt->parent = amdgpu_bo_ref(vm->page_directory);
+
                r = amdgpu_vm_clear_bo(adev, pt);
                if (r) {
                        amdgpu_bo_unref(&pt);
@@ -1150,10 +1159,13 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
        spin_unlock(&vm->it_lock);
        trace_amdgpu_vm_bo_unmap(bo_va, mapping);
 
-       if (valid)
+       if (valid) {
+               spin_lock(&vm->freed_lock);
                list_add(&mapping->list, &vm->freed);
-       else
+               spin_unlock(&vm->freed_lock);
+       } else {
                kfree(mapping);
+       }
 
        return 0;
 }
@@ -1186,7 +1198,9 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
                interval_tree_remove(&mapping->it, &vm->va);
                spin_unlock(&vm->it_lock);
                trace_amdgpu_vm_bo_unmap(bo_va, mapping);
+               spin_lock(&vm->freed_lock);
                list_add(&mapping->list, &vm->freed);
+               spin_unlock(&vm->freed_lock);
        }
        list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
                list_del(&mapping->list);
@@ -1234,7 +1248,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
 {
        const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE,
                AMDGPU_VM_PTE_COUNT * 8);
-       unsigned pd_size, pd_entries, pts_size;
+       unsigned pd_size, pd_entries;
        int i, r;
 
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
@@ -1247,12 +1261,12 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
        INIT_LIST_HEAD(&vm->cleared);
        INIT_LIST_HEAD(&vm->freed);
        spin_lock_init(&vm->it_lock);
+       spin_lock_init(&vm->freed_lock);
        pd_size = amdgpu_vm_directory_size(adev);
        pd_entries = amdgpu_vm_num_pdes(adev);
 
        /* allocate page table array */
-       pts_size = pd_entries * sizeof(struct amdgpu_vm_pt);
-       vm->page_tables = kzalloc(pts_size, GFP_KERNEL);
+       vm->page_tables = drm_calloc_large(pd_entries, sizeof(struct amdgpu_vm_pt));
        if (vm->page_tables == NULL) {
                DRM_ERROR("Cannot allocate memory for page table array\n");
                return -ENOMEM;
@@ -1312,7 +1326,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
 
        for (i = 0; i < amdgpu_vm_num_pdes(adev); i++)
                amdgpu_bo_unref(&vm->page_tables[i].bo);
-       kfree(vm->page_tables);
+       drm_free_large(vm->page_tables);
 
        amdgpu_bo_unref(&vm->page_directory);
        fence_put(vm->page_directory_fence);