aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.14.71/1554-drm-amdkfd-Fix-the-PTE-not-cleared-on-BO-unmapping-b.patch
blob: dcb738b034cb243f64a5fd408b7b8b9cecdfc8e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
From 090fd495113df59a3421e4e778b776ff8b6cd75f Mon Sep 17 00:00:00 2001
From: Yong Zhao <yong.zhao@amd.com>
Date: Mon, 31 Oct 2016 17:18:22 -0400
Subject: [PATCH 1554/4131] drm/amdkfd: Fix the PTE not cleared on BO unmapping
 bug

This bug hides very well because the BO mapping and unmapping are
working in charm to not erase the PTE and not release the vm mapping
until the BO gets freed. This is also the case for memory eviction.

We fix the bug by correctly erase the PTE and release the vm mapping
on unmapping and rewrite the PTE and recreate vm mapping on mapping.

Fix BUG: SWDEV-89590 SWDEV-106528

Change-Id: If7312e8912aedc9365f359ec99719bf76d493665
Signed-off-by: Yong Zhao <yong.zhao@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h       |   7 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 174 +++++++++++------------
 2 files changed, 87 insertions(+), 94 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index dcf2c5a..62ef856 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -41,6 +41,7 @@ struct kfd_bo_va_list {
        void *kgd_dev;
        bool is_mapped;
        bool map_fail;
+       uint64_t va;
 };
 
 struct kgd_mem {
@@ -55,9 +56,11 @@ struct kgd_mem {
         unsigned int evicted; /* eviction counter */
         struct delayed_work work; /* for restore evicted mem */
         struct mm_struct *mm; /* for restore */
+
+       uint32_t pte_flags;
+
+
         /* flags bitfield */
-        bool readonly      : 1;
-        bool execute       : 1;
         bool no_substitute : 1;
         bool aql_queue     : 1;
 };
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index ff3be96..606996e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -163,12 +163,9 @@ static int add_bo_to_vm(struct amdgpu_device *adev, struct kgd_mem *mem,
 {
 	int ret;
 	struct kfd_bo_va_list *bo_va_entry;
-	uint32_t flags;
 	struct amdgpu_bo *bo = mem->bo;
 	uint64_t va = mem->va;
 	struct list_head *list_bo_va = &mem->bo_va_list;
-	bool readonly = mem->readonly;
-	bool execute = mem->execute;
 
 	if (is_aql)
 		va += bo->tbo.mem.size;
@@ -191,23 +188,7 @@ static int add_bo_to_vm(struct amdgpu_device *adev, struct kgd_mem *mem,
 		goto err_vmadd;
 	}
 
-	flags = AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE;
-	if (readonly)
-		flags = AMDGPU_PTE_READABLE;
-	if (execute)
-		flags |= AMDGPU_PTE_EXECUTABLE;
-
-	/* Set virtual address for the allocation, allocate PTs,
-	 * if needed, and zero them */
-	ret = amdgpu_vm_bo_map(adev, bo_va_entry->bo_va,
-			va, 0, amdgpu_bo_size(bo),
-			flags | AMDGPU_PTE_VALID);
-	if (ret != 0) {
-		pr_err("amdkfd: Failed to set virtual address for BO. ret == %d (0x%llx)\n",
-				ret, va);
-		goto err_vmsetaddr;
-	}
-
+	bo_va_entry->va = va;
 	bo_va_entry->kgd_dev = (void *)adev;
 	list_add(&bo_va_entry->bo_list, list_bo_va);
 
@@ -216,12 +197,6 @@ static int add_bo_to_vm(struct amdgpu_device *adev, struct kgd_mem *mem,
 
 	return 0;
 
-err_vmsetaddr:
-	amdgpu_vm_bo_rmv(adev, bo_va_entry->bo_va);
-	/* This will put the bo_va_mapping on the vm->freed
-	 * list. amdgpu_vm_clear_freed needs the PTs to be reserved so
-	 * we don't call it here. That can wait until the next time
-	 * the page tables are updated for a map or unmap. */
 err_vmadd:
 	kfree(bo_va_entry);
 	return ret;
@@ -409,6 +384,7 @@ static int __alloc_memory_of_gpu(struct kgd_dev *kgd, uint64_t va,
 	uint64_t user_addr = 0;
 	int byte_align;
 	u32 alloc_domain;
+	uint32_t pte_flags;
 	struct amdkfd_vm *kfd_vm = (struct amdkfd_vm *)vm;
 
 	BUG_ON(kgd == NULL);
@@ -438,11 +414,18 @@ static int __alloc_memory_of_gpu(struct kgd_dev *kgd, uint64_t va,
 	}
 	INIT_LIST_HEAD(&(*mem)->bo_va_list);
 	mutex_init(&(*mem)->lock);
-	(*mem)->readonly = readonly;
-	(*mem)->execute = execute;
+
 	(*mem)->no_substitute = no_sub;
 	(*mem)->aql_queue = aql_queue;
 
+	pte_flags = AMDGPU_PTE_READABLE | AMDGPU_PTE_VALID;
+	if (!readonly)
+		pte_flags |= AMDGPU_PTE_WRITEABLE;
+	if (execute)
+		pte_flags |= AMDGPU_PTE_EXECUTABLE;
+
+	(*mem)->pte_flags = pte_flags;
+
 	alloc_domain = userptr ? AMDGPU_GEM_DOMAIN_CPU : domain;
 	pr_debug("amdkfd: allocating BO on domain %d with size %llu\n",
 				alloc_domain, size);
@@ -811,46 +794,56 @@ static int update_user_pages(struct kgd_mem *mem, struct mm_struct *mm,
 	return 0;
 }
 
-static int map_bo_to_gpuvm(struct amdgpu_device *adev, struct amdgpu_bo *bo,
-		struct amdgpu_bo_va *bo_va,
+static int unmap_bo_from_gpuvm(struct amdgpu_device *adev,
+				struct amdgpu_bo *bo,
+				struct kfd_bo_va_list *entry,
+				struct amdgpu_sync *sync)
+{
+	struct amdgpu_bo_va *bo_va = entry->bo_va;
+	struct amdgpu_vm *vm = bo_va->vm;
+
+	amdgpu_vm_bo_unmap(adev, bo_va, entry->va);
+
+	amdgpu_vm_clear_freed(adev, vm, &bo_va->last_pt_update);
+
+	amdgpu_sync_fence(adev, sync, bo_va->last_pt_update);
+
+	amdgpu_amdkfd_bo_invalidate(bo);
+
+	return 0;
+}
+
+static int update_gpuvm_pte(struct amdgpu_device *adev, struct amdgpu_bo *bo,
+		struct kfd_bo_va_list *entry,
 		struct amdgpu_sync *sync)
 {
-	struct amdgpu_vm *vm;
 	int ret;
+	struct amdgpu_vm *vm;
+	struct amdgpu_bo_va *bo_va;
 
+	bo_va = entry->bo_va;
 	vm = bo_va->vm;
 	/* Validate PT / PTs */
 	ret = validate_pt_pd_bos(vm);
 	if (ret != 0) {
-		pr_err("amdkfd: Failed to validate PTs\n");
-		goto err_unpin_bo;
+		pr_err("amdkfd: Failed to validate_pt_pd_bos\n");
+		return ret;
 	}
 
 	/* Update the page directory */
 	ret = amdgpu_vm_update_page_directory(adev, vm);
 	if (ret != 0) {
-		pr_err("amdkfd: Failed to radeon_vm_update_page_directory\n");
-		goto err_unpin_bo;
+		pr_err("amdkfd: Failed to amdgpu_vm_update_page_directory\n");
+		return ret;
 	}
 
 	amdgpu_sync_fence(adev, sync, vm->page_directory_fence);
 
-	/*
-	 * The previously "released" BOs are really released and their VAs are
-	 * removed from PT. This function is called here because it requires
-	 * the radeon_vm::mutex to be locked and PT to be reserved
-	 */
-	ret = amdgpu_vm_clear_freed(adev, vm, NULL);
-	if (ret != 0) {
-		pr_err("amdkfd: Failed to radeon_vm_clear_freed\n");
-		goto err_unpin_bo;
-	}
-
 	/* Update the page tables  */
 	ret = amdgpu_vm_bo_update(adev, bo_va, &bo->tbo.mem);
 	if (ret != 0) {
-		pr_err("amdkfd: Failed to radeon_vm_bo_update\n");
-		goto err_unpin_bo;
+		pr_err("amdkfd: Failed to amdgpu_vm_bo_update\n");
+		return ret;
 	}
 
 	amdgpu_sync_fence(adev, sync, bo_va->last_pt_update);
@@ -859,9 +852,38 @@ static int map_bo_to_gpuvm(struct amdgpu_device *adev, struct amdgpu_bo *bo,
 	amdgpu_vm_move_pt_bos_in_lru(adev, vm);
 
 	return 0;
+}
+
+static int map_bo_to_gpuvm(struct amdgpu_device *adev, struct amdgpu_bo *bo,
+		struct kfd_bo_va_list *entry, uint32_t pte_flags,
+		struct amdgpu_sync *sync)
+{
+	int ret;
+	struct amdgpu_bo_va *bo_va;
+
+	bo_va = entry->bo_va;
+	/* Set virtual address for the allocation, allocate PTs,
+	 * if needed, and zero them.
+	 */
+	ret = amdgpu_vm_bo_map(adev, bo_va,
+			entry->va, 0, amdgpu_bo_size(bo),
+			pte_flags);
+	if (ret != 0) {
+		pr_err("amdkfd: Failed to map bo in vm. ret == %d (0x%llx)\n",
+				ret, entry->va);
+		return ret;
+	}
+
+	ret = update_gpuvm_pte(adev, bo, entry, sync);
+	if (ret != 0) {
+		pr_err("amdkfd: update_gpuvm_pte() failed\n");
+		goto update_gpuvm_pte_failed;
+	}
+
+	return 0;
 
-err_unpin_bo:
-	amdgpu_amdkfd_bo_invalidate(bo);
+update_gpuvm_pte_failed:
+	unmap_bo_from_gpuvm(adev, bo, entry, sync);
 	return ret;
 }
 
@@ -1130,8 +1152,8 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
 			pr_debug("amdkfd: Trying to map VA 0x%llx to vm %p\n",
 					mem->va, vm);
 
-			ret = map_bo_to_gpuvm(adev, bo, entry->bo_va,
-					      &ctx.sync);
+			ret = map_bo_to_gpuvm(adev, bo, entry, mem->pte_flags,
+					&ctx.sync);
 			if (ret != 0) {
 				pr_err("amdkfd: Failed to map radeon bo to gpuvm\n");
 				goto map_bo_to_gpuvm_failed;
@@ -1237,15 +1259,6 @@ int amdgpu_amdkfd_gpuvm_create_process_vm(struct kgd_dev *kgd, void **vm,
 	new_vm->master->n_vms++;
 	*vm = (void *) new_vm;
 
-	/*
-	 * The previously "released" BOs are really released and their VAs are
-	 * removed from PT. This function is called here because it requires
-	 * the radeon_vm::mutex to be locked and PT to be reserved
-	 */
-	ret = amdgpu_vm_clear_freed(adev, &new_vm->base, NULL);
-	if (ret != 0)
-		pr_err("amdgpu: Failed to amdgpu_vm_clear_freed\n");
-
 	pr_debug("amdgpu: created process vm with address 0x%llx\n",
 			get_vm_pd_gpu_offset(&new_vm->base));
 
@@ -1305,29 +1318,6 @@ int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd,
 	return 0;
 }
 
-static int unmap_bo_from_gpuvm(struct amdgpu_device *adev,
-				struct amdgpu_bo *bo,
-				struct amdgpu_bo_va *bo_va,
-				struct amdgpu_sync *sync)
-{
-	struct amdgpu_vm *vm = bo_va->vm;
-
-	/*
-	 * The previously "released" BOs are really released and their VAs are
-	 * removed from PT. This function is called here because it requires
-	 * the radeon_vm::mutex to be locked and PT to be reserved
-	 */
-	amdgpu_vm_clear_freed(adev, vm, NULL);
-
-	/* Update the page tables - Remove the mapping from bo_va */
-	amdgpu_vm_bo_update(adev, bo_va, NULL);
-	amdgpu_sync_fence(adev, sync, bo_va->last_pt_update);
-
-	amdgpu_amdkfd_bo_invalidate(bo);
-
-	return 0;
-}
-
 static bool is_mem_on_local_device(struct kgd_dev *kgd,
 		struct list_head *bo_va_list, void *vm)
 {
@@ -1396,7 +1386,7 @@ int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
 				mem->bo->tbo.mem.size);
 
 			ret = unmap_bo_from_gpuvm(adev, mem->bo,
-						entry->bo_va, &ctx.sync);
+						entry, &ctx.sync);
 			if (ret == 0) {
 				entry->is_mapped = false;
 			} else {
@@ -1686,8 +1676,8 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd, int dma_buf_fd,
 
 	INIT_LIST_HEAD(&(*mem)->bo_va_list);
 	mutex_init(&(*mem)->lock);
-	(*mem)->readonly = false;
-	(*mem)->execute = true; /* executable by default */
+	(*mem)->pte_flags = AMDGPU_PTE_READABLE | AMDGPU_PTE_VALID
+			| AMDGPU_PTE_WRITEABLE | AMDGPU_PTE_EXECUTABLE;
 
 	(*mem)->bo = amdgpu_bo_ref(bo);
 	(*mem)->va = va;
@@ -1750,7 +1740,7 @@ int amdgpu_amdkfd_gpuvm_evict_mem(struct kgd_mem *mem, struct mm_struct *mm)
 		adev = (struct amdgpu_device *)entry->kgd_dev;
 
 		r = unmap_bo_from_gpuvm(adev, mem->bo,
-					entry->bo_va, &ctx.sync);
+					entry, &ctx.sync);
 		if (r != 0) {
 			pr_err("failed unmap va 0x%llx\n",
 			       mem->va);
@@ -1849,8 +1839,8 @@ int amdgpu_amdkfd_gpuvm_restore_mem(struct kgd_mem *mem, struct mm_struct *mm)
 			continue;
 		}
 
-		r = map_bo_to_gpuvm(adev, mem->bo, entry->bo_va,
-				    &ctx.sync);
+		r = map_bo_to_gpuvm(adev, mem->bo, entry, mem->pte_flags,
+				&ctx.sync);
 		if (unlikely(r != 0)) {
 			pr_err("Failed to map BO to gpuvm\n");
 			entry->map_fail = true;
@@ -2026,9 +2016,9 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *m_vm)
 
 		list_for_each_entry(bo_va_entry, &mem->bo_va_list,
 				    bo_list) {
-			ret = map_bo_to_gpuvm((struct amdgpu_device *)
+			ret = update_gpuvm_pte((struct amdgpu_device *)
 					      bo_va_entry->kgd_dev,
-					      bo, bo_va_entry->bo_va,
+					      bo, bo_va_entry,
 					      &ctx.sync);
 			if (ret) {
 				pr_debug("Memory eviction: Map failed. Try again\n");
-- 
2.7.4