diff options
author | Felix Kuehling <Felix.Kuehling@amd.com> | 2018-03-15 17:27:48 -0400 |
---|---|---|
committer | Oded Gabbay <oded.gabbay@gmail.com> | 2018-03-15 17:27:48 -0400 |
commit | 52b29d73340da6cbb10ba42b0a28e7fb795afe9c (patch) | |
tree | ba1d240c9bf1591c098c72fa8c327a7ba5f944eb | |
parent | d01994c24cb28b6f200138d98cbfc17b6bd967c5 (diff) |
drm/amdkfd: Add per-process IDR for buffer handles
Also used for cleaning up on process termination.
v2: Refactored cleanup on process termination
Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdkfd/kfd_process.c | 73 |
2 files changed, 84 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 0d5d924b31ef..b2b5ef8c4536 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h | |||
@@ -543,6 +543,9 @@ struct kfd_process_device { | |||
543 | struct file *drm_file; | 543 | struct file *drm_file; |
544 | void *vm; | 544 | void *vm; |
545 | 545 | ||
546 | /* GPUVM allocations storage */ | ||
547 | struct idr alloc_idr; | ||
548 | |||
546 | /* Flag used to tell the pdd has dequeued from the dqm. | 549 | /* Flag used to tell the pdd has dequeued from the dqm. |
547 | * This is used to prevent dev->dqm->ops.process_termination() from | 550 | * This is used to prevent dev->dqm->ops.process_termination() from |
548 | * being called twice when it is already called in IOMMU callback | 551 | * being called twice when it is already called in IOMMU callback |
@@ -678,6 +681,14 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev, | |||
678 | int kfd_reserved_mem_mmap(struct kfd_process *process, | 681 | int kfd_reserved_mem_mmap(struct kfd_process *process, |
679 | struct vm_area_struct *vma); | 682 | struct vm_area_struct *vma); |
680 | 683 | ||
684 | /* KFD process API for creating and translating handles */ | ||
685 | int kfd_process_device_create_obj_handle(struct kfd_process_device *pdd, | ||
686 | void *mem); | ||
687 | void *kfd_process_device_translate_handle(struct kfd_process_device *p, | ||
688 | int handle); | ||
689 | void kfd_process_device_remove_obj_handle(struct kfd_process_device *pdd, | ||
690 | int handle); | ||
691 | |||
681 | /* Process device data iterator */ | 692 | /* Process device data iterator */ |
682 | struct kfd_process_device *kfd_get_first_process_device_data( | 693 | struct kfd_process_device *kfd_get_first_process_device_data( |
683 | struct kfd_process *p); | 694 | struct kfd_process *p); |
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 6618aaa6b84f..a2ae0236a3ea 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c | |||
@@ -150,6 +150,40 @@ void kfd_unref_process(struct kfd_process *p) | |||
150 | kref_put(&p->ref, kfd_process_ref_release); | 150 | kref_put(&p->ref, kfd_process_ref_release); |
151 | } | 151 | } |
152 | 152 | ||
153 | static void kfd_process_device_free_bos(struct kfd_process_device *pdd) | ||
154 | { | ||
155 | struct kfd_process *p = pdd->process; | ||
156 | void *mem; | ||
157 | int id; | ||
158 | |||
159 | /* | ||
160 | * Remove all handles from idr and release appropriate | ||
161 | * local memory object | ||
162 | */ | ||
163 | idr_for_each_entry(&pdd->alloc_idr, mem, id) { | ||
164 | struct kfd_process_device *peer_pdd; | ||
165 | |||
166 | list_for_each_entry(peer_pdd, &p->per_device_data, | ||
167 | per_device_list) { | ||
168 | if (!peer_pdd->vm) | ||
169 | continue; | ||
170 | peer_pdd->dev->kfd2kgd->unmap_memory_to_gpu( | ||
171 | peer_pdd->dev->kgd, mem, peer_pdd->vm); | ||
172 | } | ||
173 | |||
174 | pdd->dev->kfd2kgd->free_memory_of_gpu(pdd->dev->kgd, mem); | ||
175 | kfd_process_device_remove_obj_handle(pdd, id); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static void kfd_process_free_outstanding_kfd_bos(struct kfd_process *p) | ||
180 | { | ||
181 | struct kfd_process_device *pdd; | ||
182 | |||
183 | list_for_each_entry(pdd, &p->per_device_data, per_device_list) | ||
184 | kfd_process_device_free_bos(pdd); | ||
185 | } | ||
186 | |||
153 | static void kfd_process_destroy_pdds(struct kfd_process *p) | 187 | static void kfd_process_destroy_pdds(struct kfd_process *p) |
154 | { | 188 | { |
155 | struct kfd_process_device *pdd, *temp; | 189 | struct kfd_process_device *pdd, *temp; |
@@ -171,6 +205,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) | |||
171 | free_pages((unsigned long)pdd->qpd.cwsr_kaddr, | 205 | free_pages((unsigned long)pdd->qpd.cwsr_kaddr, |
172 | get_order(KFD_CWSR_TBA_TMA_SIZE)); | 206 | get_order(KFD_CWSR_TBA_TMA_SIZE)); |
173 | 207 | ||
208 | idr_destroy(&pdd->alloc_idr); | ||
209 | |||
174 | kfree(pdd); | 210 | kfree(pdd); |
175 | } | 211 | } |
176 | } | 212 | } |
@@ -187,6 +223,8 @@ static void kfd_process_wq_release(struct work_struct *work) | |||
187 | 223 | ||
188 | kfd_iommu_unbind_process(p); | 224 | kfd_iommu_unbind_process(p); |
189 | 225 | ||
226 | kfd_process_free_outstanding_kfd_bos(p); | ||
227 | |||
190 | kfd_process_destroy_pdds(p); | 228 | kfd_process_destroy_pdds(p); |
191 | dma_fence_put(p->ef); | 229 | dma_fence_put(p->ef); |
192 | 230 | ||
@@ -371,6 +409,7 @@ static struct kfd_process *create_process(const struct task_struct *thread, | |||
371 | return process; | 409 | return process; |
372 | 410 | ||
373 | err_init_cwsr: | 411 | err_init_cwsr: |
412 | kfd_process_free_outstanding_kfd_bos(process); | ||
374 | kfd_process_destroy_pdds(process); | 413 | kfd_process_destroy_pdds(process); |
375 | err_init_apertures: | 414 | err_init_apertures: |
376 | pqm_uninit(&process->pqm); | 415 | pqm_uninit(&process->pqm); |
@@ -421,6 +460,9 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev, | |||
421 | pdd->already_dequeued = false; | 460 | pdd->already_dequeued = false; |
422 | list_add(&pdd->per_device_list, &p->per_device_data); | 461 | list_add(&pdd->per_device_list, &p->per_device_data); |
423 | 462 | ||
463 | /* Init idr used for memory handle translation */ | ||
464 | idr_init(&pdd->alloc_idr); | ||
465 | |||
424 | return pdd; | 466 | return pdd; |
425 | } | 467 | } |
426 | 468 | ||
@@ -520,6 +562,37 @@ bool kfd_has_process_device_data(struct kfd_process *p) | |||
520 | return !(list_empty(&p->per_device_data)); | 562 | return !(list_empty(&p->per_device_data)); |
521 | } | 563 | } |
522 | 564 | ||
565 | /* Create specific handle mapped to mem from process local memory idr | ||
566 | * Assumes that the process lock is held. | ||
567 | */ | ||
568 | int kfd_process_device_create_obj_handle(struct kfd_process_device *pdd, | ||
569 | void *mem) | ||
570 | { | ||
571 | return idr_alloc(&pdd->alloc_idr, mem, 0, 0, GFP_KERNEL); | ||
572 | } | ||
573 | |||
574 | /* Translate specific handle from process local memory idr | ||
575 | * Assumes that the process lock is held. | ||
576 | */ | ||
577 | void *kfd_process_device_translate_handle(struct kfd_process_device *pdd, | ||
578 | int handle) | ||
579 | { | ||
580 | if (handle < 0) | ||
581 | return NULL; | ||
582 | |||
583 | return idr_find(&pdd->alloc_idr, handle); | ||
584 | } | ||
585 | |||
586 | /* Remove specific handle from process local memory idr | ||
587 | * Assumes that the process lock is held. | ||
588 | */ | ||
589 | void kfd_process_device_remove_obj_handle(struct kfd_process_device *pdd, | ||
590 | int handle) | ||
591 | { | ||
592 | if (handle >= 0) | ||
593 | idr_remove(&pdd->alloc_idr, handle); | ||
594 | } | ||
595 | |||
523 | /* This increments the process->ref counter. */ | 596 | /* This increments the process->ref counter. */ |
524 | struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid) | 597 | struct kfd_process *kfd_lookup_process_by_pasid(unsigned int pasid) |
525 | { | 598 | { |