aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorOak Zeng <Oak.Zeng@amd.com>2018-09-05 23:51:23 -0400
committerAlex Deucher <alexander.deucher@amd.com>2018-09-12 17:28:53 -0400
commit240cd9a64226e013ac1a608ebf720a1813790196 (patch)
treede0ab86452ec57fc396591708230ee549e98bac4 /drivers/gpu
parent7e7bf8de432db3de912050856e641458de72a7b1 (diff)
drm/amdgpu: Move fault hash table to amdgpu vm
In stead of share one fault hash table per device, make it per vm. This can avoid inter-process lock issue when fault hash table is full. Change-Id: I5d1281b7c41eddc8e26113e010516557588d3708 Signed-off-by: Oak Zeng <Oak.Zeng@amd.com> Suggested-by: Christian Konig <Christian.Koenig@amd.com> Suggested-by: Felix Kuehling <Felix.Kuehling@amd.com> Reviewed-by: Christian Konig <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c75
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c102
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vega10_ih.c38
5 files changed, 128 insertions, 111 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
index 06373d44b3da..4ed86218cef3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
@@ -197,78 +197,3 @@ restart_ih:
197 return IRQ_HANDLED; 197 return IRQ_HANDLED;
198} 198}
199 199
200/**
201 * amdgpu_ih_add_fault - Add a page fault record
202 *
203 * @adev: amdgpu device pointer
204 * @key: 64-bit encoding of PASID and address
205 *
206 * This should be called when a retry page fault interrupt is
207 * received. If this is a new page fault, it will be added to a hash
208 * table. The return value indicates whether this is a new fault, or
209 * a fault that was already known and is already being handled.
210 *
211 * If there are too many pending page faults, this will fail. Retry
212 * interrupts should be ignored in this case until there is enough
213 * free space.
214 *
215 * Returns 0 if the fault was added, 1 if the fault was already known,
216 * -ENOSPC if there are too many pending faults.
217 */
218int amdgpu_ih_add_fault(struct amdgpu_device *adev, u64 key)
219{
220 unsigned long flags;
221 int r = -ENOSPC;
222
223 if (WARN_ON_ONCE(!adev->irq.ih.faults))
224 /* Should be allocated in <IP>_ih_sw_init on GPUs that
225 * support retry faults and require retry filtering.
226 */
227 return r;
228
229 spin_lock_irqsave(&adev->irq.ih.faults->lock, flags);
230
231 /* Only let the hash table fill up to 50% for best performance */
232 if (adev->irq.ih.faults->count >= (1 << (AMDGPU_PAGEFAULT_HASH_BITS-1)))
233 goto unlock_out;
234
235 r = chash_table_copy_in(&adev->irq.ih.faults->hash, key, NULL);
236 if (!r)
237 adev->irq.ih.faults->count++;
238
239 /* chash_table_copy_in should never fail unless we're losing count */
240 WARN_ON_ONCE(r < 0);
241
242unlock_out:
243 spin_unlock_irqrestore(&adev->irq.ih.faults->lock, flags);
244 return r;
245}
246
247/**
248 * amdgpu_ih_clear_fault - Remove a page fault record
249 *
250 * @adev: amdgpu device pointer
251 * @key: 64-bit encoding of PASID and address
252 *
253 * This should be called when a page fault has been handled. Any
254 * future interrupt with this key will be processed as a new
255 * page fault.
256 */
257void amdgpu_ih_clear_fault(struct amdgpu_device *adev, u64 key)
258{
259 unsigned long flags;
260 int r;
261
262 if (!adev->irq.ih.faults)
263 return;
264
265 spin_lock_irqsave(&adev->irq.ih.faults->lock, flags);
266
267 r = chash_table_remove(&adev->irq.ih.faults->hash, key, NULL);
268 if (!WARN_ON_ONCE(r < 0)) {
269 adev->irq.ih.faults->count--;
270 WARN_ON_ONCE(adev->irq.ih.faults->count < 0);
271 }
272
273 spin_unlock_irqrestore(&adev->irq.ih.faults->lock, flags);
274}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
index a23e1c0bed93..0d5b3f5201d2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
@@ -24,7 +24,6 @@
24#ifndef __AMDGPU_IH_H__ 24#ifndef __AMDGPU_IH_H__
25#define __AMDGPU_IH_H__ 25#define __AMDGPU_IH_H__
26 26
27#include <linux/chash.h>
28#include "soc15_ih_clientid.h" 27#include "soc15_ih_clientid.h"
29 28
30struct amdgpu_device; 29struct amdgpu_device;
@@ -32,13 +31,6 @@ struct amdgpu_device;
32#define AMDGPU_IH_CLIENTID_LEGACY 0 31#define AMDGPU_IH_CLIENTID_LEGACY 0
33#define AMDGPU_IH_CLIENTID_MAX SOC15_IH_CLIENTID_MAX 32#define AMDGPU_IH_CLIENTID_MAX SOC15_IH_CLIENTID_MAX
34 33
35#define AMDGPU_PAGEFAULT_HASH_BITS 8
36struct amdgpu_retryfault_hashtable {
37 DECLARE_CHASH_TABLE(hash, AMDGPU_PAGEFAULT_HASH_BITS, 8, 0);
38 spinlock_t lock;
39 int count;
40};
41
42/* 34/*
43 * R6xx+ IH ring 35 * R6xx+ IH ring
44 */ 36 */
@@ -57,7 +49,6 @@ struct amdgpu_ih_ring {
57 bool use_doorbell; 49 bool use_doorbell;
58 bool use_bus_addr; 50 bool use_bus_addr;
59 dma_addr_t rb_dma_addr; /* only used when use_bus_addr = true */ 51 dma_addr_t rb_dma_addr; /* only used when use_bus_addr = true */
60 struct amdgpu_retryfault_hashtable *faults;
61}; 52};
62 53
63#define AMDGPU_IH_SRC_DATA_MAX_SIZE_DW 4 54#define AMDGPU_IH_SRC_DATA_MAX_SIZE_DW 4
@@ -95,7 +86,5 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size,
95 bool use_bus_addr); 86 bool use_bus_addr);
96void amdgpu_ih_ring_fini(struct amdgpu_device *adev); 87void amdgpu_ih_ring_fini(struct amdgpu_device *adev);
97int amdgpu_ih_process(struct amdgpu_device *adev); 88int amdgpu_ih_process(struct amdgpu_device *adev);
98int amdgpu_ih_add_fault(struct amdgpu_device *adev, u64 key);
99void amdgpu_ih_clear_fault(struct amdgpu_device *adev, u64 key);
100 89
101#endif 90#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 136b00412dc8..be1659fedf94 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -2717,6 +2717,22 @@ void amdgpu_vm_adjust_size(struct amdgpu_device *adev, uint32_t min_vm_size,
2717 adev->vm_manager.fragment_size); 2717 adev->vm_manager.fragment_size);
2718} 2718}
2719 2719
2720static struct amdgpu_retryfault_hashtable *init_fault_hash(void)
2721{
2722 struct amdgpu_retryfault_hashtable *fault_hash;
2723
2724 fault_hash = kmalloc(sizeof(*fault_hash), GFP_KERNEL);
2725 if (!fault_hash)
2726 return fault_hash;
2727
2728 INIT_CHASH_TABLE(fault_hash->hash,
2729 AMDGPU_PAGEFAULT_HASH_BITS, 8, 0);
2730 spin_lock_init(&fault_hash->lock);
2731 fault_hash->count = 0;
2732
2733 return fault_hash;
2734}
2735
2720/** 2736/**
2721 * amdgpu_vm_init - initialize a vm instance 2737 * amdgpu_vm_init - initialize a vm instance
2722 * 2738 *
@@ -2805,6 +2821,12 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
2805 vm->pasid = pasid; 2821 vm->pasid = pasid;
2806 } 2822 }
2807 2823
2824 vm->fault_hash = init_fault_hash();
2825 if (!vm->fault_hash) {
2826 r = -ENOMEM;
2827 goto error_free_root;
2828 }
2829
2808 INIT_KFIFO(vm->faults); 2830 INIT_KFIFO(vm->faults);
2809 vm->fault_credit = 16; 2831 vm->fault_credit = 16;
2810 2832
@@ -2998,7 +3020,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
2998 3020
2999 /* Clear pending page faults from IH when the VM is destroyed */ 3021 /* Clear pending page faults from IH when the VM is destroyed */
3000 while (kfifo_get(&vm->faults, &fault)) 3022 while (kfifo_get(&vm->faults, &fault))
3001 amdgpu_ih_clear_fault(adev, fault); 3023 amdgpu_vm_clear_fault(vm->fault_hash, fault);
3002 3024
3003 if (vm->pasid) { 3025 if (vm->pasid) {
3004 unsigned long flags; 3026 unsigned long flags;
@@ -3008,6 +3030,9 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
3008 spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags); 3030 spin_unlock_irqrestore(&adev->vm_manager.pasid_lock, flags);
3009 } 3031 }
3010 3032
3033 kfree(vm->fault_hash);
3034 vm->fault_hash = NULL;
3035
3011 drm_sched_entity_destroy(&vm->entity); 3036 drm_sched_entity_destroy(&vm->entity);
3012 3037
3013 if (!RB_EMPTY_ROOT(&vm->va.rb_root)) { 3038 if (!RB_EMPTY_ROOT(&vm->va.rb_root)) {
@@ -3208,3 +3233,78 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm)
3208 } 3233 }
3209 } 3234 }
3210} 3235}
3236
3237/**
3238 * amdgpu_vm_add_fault - Add a page fault record to fault hash table
3239 *
3240 * @fault_hash: fault hash table
3241 * @key: 64-bit encoding of PASID and address
3242 *
3243 * This should be called when a retry page fault interrupt is
3244 * received. If this is a new page fault, it will be added to a hash
3245 * table. The return value indicates whether this is a new fault, or
3246 * a fault that was already known and is already being handled.
3247 *
3248 * If there are too many pending page faults, this will fail. Retry
3249 * interrupts should be ignored in this case until there is enough
3250 * free space.
3251 *
3252 * Returns 0 if the fault was added, 1 if the fault was already known,
3253 * -ENOSPC if there are too many pending faults.
3254 */
3255int amdgpu_vm_add_fault(struct amdgpu_retryfault_hashtable *fault_hash, u64 key)
3256{
3257 unsigned long flags;
3258 int r = -ENOSPC;
3259
3260 if (WARN_ON_ONCE(!fault_hash))
3261 /* Should be allocated in amdgpu_vm_init
3262 */
3263 return r;
3264
3265 spin_lock_irqsave(&fault_hash->lock, flags);
3266
3267 /* Only let the hash table fill up to 50% for best performance */
3268 if (fault_hash->count >= (1 << (AMDGPU_PAGEFAULT_HASH_BITS-1)))
3269 goto unlock_out;
3270
3271 r = chash_table_copy_in(&fault_hash->hash, key, NULL);
3272 if (!r)
3273 fault_hash->count++;
3274
3275 /* chash_table_copy_in should never fail unless we're losing count */
3276 WARN_ON_ONCE(r < 0);
3277
3278unlock_out:
3279 spin_unlock_irqrestore(&fault_hash->lock, flags);
3280 return r;
3281}
3282
3283/**
3284 * amdgpu_vm_clear_fault - Remove a page fault record
3285 *
3286 * @fault_hash: fault hash table
3287 * @key: 64-bit encoding of PASID and address
3288 *
3289 * This should be called when a page fault has been handled. Any
3290 * future interrupt with this key will be processed as a new
3291 * page fault.
3292 */
3293void amdgpu_vm_clear_fault(struct amdgpu_retryfault_hashtable *fault_hash, u64 key)
3294{
3295 unsigned long flags;
3296 int r;
3297
3298 if (!fault_hash)
3299 return;
3300
3301 spin_lock_irqsave(&fault_hash->lock, flags);
3302
3303 r = chash_table_remove(&fault_hash->hash, key, NULL);
3304 if (!WARN_ON_ONCE(r < 0)) {
3305 fault_hash->count--;
3306 WARN_ON_ONCE(fault_hash->count < 0);
3307 }
3308
3309 spin_unlock_irqrestore(&fault_hash->lock, flags);
3310}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index e275ee7c1bc1..12d21eec4568 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -30,6 +30,7 @@
30#include <drm/gpu_scheduler.h> 30#include <drm/gpu_scheduler.h>
31#include <drm/drm_file.h> 31#include <drm/drm_file.h>
32#include <drm/ttm/ttm_bo_driver.h> 32#include <drm/ttm/ttm_bo_driver.h>
33#include <linux/chash.h>
33 34
34#include "amdgpu_sync.h" 35#include "amdgpu_sync.h"
35#include "amdgpu_ring.h" 36#include "amdgpu_ring.h"
@@ -178,6 +179,13 @@ struct amdgpu_task_info {
178 pid_t tgid; 179 pid_t tgid;
179}; 180};
180 181
182#define AMDGPU_PAGEFAULT_HASH_BITS 8
183struct amdgpu_retryfault_hashtable {
184 DECLARE_CHASH_TABLE(hash, AMDGPU_PAGEFAULT_HASH_BITS, 8, 0);
185 spinlock_t lock;
186 int count;
187};
188
181struct amdgpu_vm { 189struct amdgpu_vm {
182 /* tree of virtual addresses mapped */ 190 /* tree of virtual addresses mapped */
183 struct rb_root_cached va; 191 struct rb_root_cached va;
@@ -240,6 +248,7 @@ struct amdgpu_vm {
240 struct ttm_lru_bulk_move lru_bulk_move; 248 struct ttm_lru_bulk_move lru_bulk_move;
241 /* mark whether can do the bulk move */ 249 /* mark whether can do the bulk move */
242 bool bulk_moveable; 250 bool bulk_moveable;
251 struct amdgpu_retryfault_hashtable *fault_hash;
243}; 252};
244 253
245struct amdgpu_vm_manager { 254struct amdgpu_vm_manager {
@@ -355,4 +364,8 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm);
355void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev, 364void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev,
356 struct amdgpu_vm *vm); 365 struct amdgpu_vm *vm);
357 366
367int amdgpu_vm_add_fault(struct amdgpu_retryfault_hashtable *fault_hash, u64 key);
368
369void amdgpu_vm_clear_fault(struct amdgpu_retryfault_hashtable *fault_hash, u64 key);
370
358#endif 371#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
index 5ae5ed2e62d6..acbe5a770207 100644
--- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
+++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c
@@ -265,35 +265,36 @@ static bool vega10_ih_prescreen_iv(struct amdgpu_device *adev)
265 return true; 265 return true;
266 } 266 }
267 267
268 addr = ((u64)(dw5 & 0xf) << 44) | ((u64)dw4 << 12);
269 key = AMDGPU_VM_FAULT(pasid, addr);
270 r = amdgpu_ih_add_fault(adev, key);
271
272 /* Hash table is full or the fault is already being processed,
273 * ignore further page faults
274 */
275 if (r != 0)
276 goto ignore_iv;
277
278 /* Track retry faults in per-VM fault FIFO. */ 268 /* Track retry faults in per-VM fault FIFO. */
279 spin_lock(&adev->vm_manager.pasid_lock); 269 spin_lock(&adev->vm_manager.pasid_lock);
280 vm = idr_find(&adev->vm_manager.pasid_idr, pasid); 270 vm = idr_find(&adev->vm_manager.pasid_idr, pasid);
271 addr = ((u64)(dw5 & 0xf) << 44) | ((u64)dw4 << 12);
272 key = AMDGPU_VM_FAULT(pasid, addr);
281 if (!vm) { 273 if (!vm) {
282 /* VM not found, process it normally */ 274 /* VM not found, process it normally */
283 spin_unlock(&adev->vm_manager.pasid_lock); 275 spin_unlock(&adev->vm_manager.pasid_lock);
284 amdgpu_ih_clear_fault(adev, key);
285 return true; 276 return true;
277 } else {
278 r = amdgpu_vm_add_fault(vm->fault_hash, key);
279
280 /* Hash table is full or the fault is already being processed,
281 * ignore further page faults
282 */
283 if (r != 0) {
284 spin_unlock(&adev->vm_manager.pasid_lock);
285 goto ignore_iv;
286 }
286 } 287 }
287 /* No locking required with single writer and single reader */ 288 /* No locking required with single writer and single reader */
288 r = kfifo_put(&vm->faults, key); 289 r = kfifo_put(&vm->faults, key);
289 if (!r) { 290 if (!r) {
290 /* FIFO is full. Ignore it until there is space */ 291 /* FIFO is full. Ignore it until there is space */
292 amdgpu_vm_clear_fault(vm->fault_hash, key);
291 spin_unlock(&adev->vm_manager.pasid_lock); 293 spin_unlock(&adev->vm_manager.pasid_lock);
292 amdgpu_ih_clear_fault(adev, key);
293 goto ignore_iv; 294 goto ignore_iv;
294 } 295 }
295 spin_unlock(&adev->vm_manager.pasid_lock);
296 296
297 spin_unlock(&adev->vm_manager.pasid_lock);
297 /* It's the first fault for this address, process it normally */ 298 /* It's the first fault for this address, process it normally */
298 return true; 299 return true;
299 300
@@ -386,14 +387,6 @@ static int vega10_ih_sw_init(void *handle)
386 adev->irq.ih.use_doorbell = true; 387 adev->irq.ih.use_doorbell = true;
387 adev->irq.ih.doorbell_index = AMDGPU_DOORBELL64_IH << 1; 388 adev->irq.ih.doorbell_index = AMDGPU_DOORBELL64_IH << 1;
388 389
389 adev->irq.ih.faults = kmalloc(sizeof(*adev->irq.ih.faults), GFP_KERNEL);
390 if (!adev->irq.ih.faults)
391 return -ENOMEM;
392 INIT_CHASH_TABLE(adev->irq.ih.faults->hash,
393 AMDGPU_PAGEFAULT_HASH_BITS, 8, 0);
394 spin_lock_init(&adev->irq.ih.faults->lock);
395 adev->irq.ih.faults->count = 0;
396
397 r = amdgpu_irq_init(adev); 390 r = amdgpu_irq_init(adev);
398 391
399 return r; 392 return r;
@@ -406,9 +399,6 @@ static int vega10_ih_sw_fini(void *handle)
406 amdgpu_irq_fini(adev); 399 amdgpu_irq_fini(adev);
407 amdgpu_ih_ring_fini(adev); 400 amdgpu_ih_ring_fini(adev);
408 401
409 kfree(adev->irq.ih.faults);
410 adev->irq.ih.faults = NULL;
411
412 return 0; 402 return 0;
413} 403}
414 404