[PATCH] drm/amdkfd: Separate pinned BOs destruction from general routine

Yu, Lang Lang.Yu at amd.com
Thu Oct 14 10:14:17 UTC 2021


[AMD Official Use Only]



>-----Original Message-----
>From: Kuehling, Felix <Felix.Kuehling at amd.com>
>Sent: Wednesday, October 13, 2021 11:25 PM
>To: Yu, Lang <Lang.Yu at amd.com>; amd-gfx at lists.freedesktop.org
>Cc: Koenig, Christian <Christian.Koenig at amd.com>; Deucher, Alexander
><Alexander.Deucher at amd.com>; Huang, Ray <Ray.Huang at amd.com>
>Subject: Re: [PATCH] drm/amdkfd: Separate pinned BOs destruction from
>general routine
>
>Am 2021-10-11 um 4:58 a.m. schrieb Lang Yu:
>> Currently, all kfd BOs use same destruction routine. But pinned BOs
>> are not unpinned properly. Separate them from general routine.
>>
>> Signed-off-by: Lang Yu <lang.yu at amd.com>
>
>I think the general idea is right. However, we need another safeguard for the
>signal BO, which is allocated by user mode and can be freed by user mode at
>any time. We can solve this in one of two ways:
>
> 1. Add special handling for the signal BO in
>    kfd_ioctl_free_memory_of_gpu to kunmap the BO and make sure the
>    signal handling code is aware of it
> 2. Fail kfd_ioctl_free_memory_of_gpu for signal BOs and only allow them
>    to be destroyed at process termination
>
>I think #2 is easier, and is consistent with what current user mode does.

Will add safeguard to prevent that according to #2.
 
>
>A few more comment inline ...
>
>
>> ---
>>  drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h    |   2 +
>>  .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c  |  10 ++
>>  drivers/gpu/drm/amd/amdkfd/kfd_chardev.c      |   3 +
>>  drivers/gpu/drm/amd/amdkfd/kfd_priv.h         |   3 +
>>  drivers/gpu/drm/amd/amdkfd/kfd_process.c      | 125 ++++++++++++++---
>-
>>  5 files changed, 114 insertions(+), 29 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>> index 69de31754907..751557af09bb 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>> @@ -279,6 +279,8 @@ int amdgpu_amdkfd_gpuvm_sync_memory(
>>  		struct kgd_dev *kgd, struct kgd_mem *mem, bool intr);  int
>> amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd,
>>  		struct kgd_mem *mem, void **kptr, uint64_t *size);
>> +void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct
>kgd_dev
>> +*kgd, struct kgd_mem *mem);
>> +
>>  int amdgpu_amdkfd_gpuvm_restore_process_bos(void *process_info,
>>  					    struct dma_fence **ef);
>>  int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd, diff
>> --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
>> index 054c1a224def..6acc78b02bdc 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
>> @@ -1871,6 +1871,16 @@ int
>amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd,
>>  	return ret;
>>  }
>>
>> +void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct
>kgd_dev
>> +*kgd, struct kgd_mem *mem) {
>> +	struct amdgpu_bo *bo = mem->bo;
>> +
>> +	amdgpu_bo_reserve(bo, true);
>> +	amdgpu_bo_kunmap(bo);
>> +	amdgpu_bo_unpin(bo);
>> +	amdgpu_bo_unreserve(bo);
>> +}
>> +
>>  int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd,
>>  					      struct kfd_vm_fault_info *mem)
>{ diff --git
>> a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> index f1e7edeb4e6b..0db48ac10fde 100644
>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>> @@ -1051,6 +1051,9 @@ static int kfd_ioctl_create_event(struct file *filp,
>struct kfd_process *p,
>>  			pr_err("Failed to set event page\n");
>
>Need to kunmap the signal BO here.

Will kunmap it here.

>
>>  			return err;
>>  		}
>> +
>> +		p->signal_handle = args->event_page_offset;
>> +
>>  	}
>>
>>  	err = kfd_event_create(filp, p, args->event_type, diff --git
>> a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>> b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>> index 6d8f9bb2d905..30f08f1606bb 100644
>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>> @@ -608,12 +608,14 @@ struct qcm_process_device {
>>  	uint32_t sh_hidden_private_base;
>>
>>  	/* CWSR memory */
>> +	struct kgd_mem *cwsr_mem;
>>  	void *cwsr_kaddr;
>>  	uint64_t cwsr_base;
>>  	uint64_t tba_addr;
>>  	uint64_t tma_addr;
>>
>>  	/* IB memory */
>> +	struct kgd_mem *ib_mem;
>>  	uint64_t ib_base;
>>  	void *ib_kaddr;
>>
>> @@ -808,6 +810,7 @@ struct kfd_process {
>>  	/* Event ID allocator and lookup */
>>  	struct idr event_idr;
>>  	/* Event page */
>> +	u64 signal_handle;
>>  	struct kfd_signal_page *signal_page;
>>  	size_t signal_mapped_size;
>>  	size_t signal_event_count;
>> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
>> b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
>> index 21ec8a18cad2..c024f2e2efaa 100644
>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
>> @@ -72,6 +72,8 @@ static int kfd_process_init_cwsr_apu(struct
>> kfd_process *p, struct file *filep);  static void
>> evict_process_worker(struct work_struct *work);  static void
>> restore_process_worker(struct work_struct *work);
>>
>> +static void kfd_process_device_destroy_cwsr_dgpu(struct
>> +kfd_process_device *pdd);
>> +
>>  struct kfd_procfs_tree {
>>  	struct kobject *kobj;
>>  };
>> @@ -685,10 +687,15 @@ void kfd_process_destroy_wq(void)  }
>>
>>  static void kfd_process_free_gpuvm(struct kgd_mem *mem,
>> -			struct kfd_process_device *pdd)
>> +			struct kfd_process_device *pdd, void *kptr)
>>  {
>>  	struct kfd_dev *dev = pdd->dev;
>>
>> +	if (kptr) {
>> +		amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(dev-
>>kgd, mem);
>> +		kptr = NULL;
>> +	}
>> +
>>  	amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(dev->kgd,
>mem, pdd->drm_priv);
>>  	amdgpu_amdkfd_gpuvm_free_memory_of_gpu(dev->kgd, mem,
>pdd->drm_priv,
>>  					       NULL);
>> @@ -702,63 +709,46 @@ static void kfd_process_free_gpuvm(struct
>kgd_mem *mem,
>>   */
>>  static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd,
>>  				   uint64_t gpu_va, uint32_t size,
>> -				   uint32_t flags, void **kptr)
>> +				   uint32_t flags, struct kgd_mem **mem, void
>**kptr)
>>  {
>>  	struct kfd_dev *kdev = pdd->dev;
>> -	struct kgd_mem *mem = NULL;
>> -	int handle;
>>  	int err;
>>
>>  	err = amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(kdev->kgd,
>gpu_va, size,
>> -						 pdd->drm_priv, &mem, NULL,
>flags);
>> +						 pdd->drm_priv, mem, NULL,
>flags);
>>  	if (err)
>>  		goto err_alloc_mem;
>>
>> -	err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd,
>mem,
>> +	err = amdgpu_amdkfd_gpuvm_map_memory_to_gpu(kdev->kgd,
>*mem,
>>  			pdd->drm_priv, NULL);
>>  	if (err)
>>  		goto err_map_mem;
>>
>> -	err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->kgd, mem,
>true);
>> +	err = amdgpu_amdkfd_gpuvm_sync_memory(kdev->kgd, *mem,
>true);
>>  	if (err) {
>>  		pr_debug("Sync memory failed, wait interrupted by user
>signal\n");
>>  		goto sync_memory_failed;
>>  	}
>>
>> -	/* Create an obj handle so kfd_process_device_remove_obj_handle
>> -	 * will take care of the bo removal when the process finishes.
>> -	 * We do not need to take p->mutex, because the process is just
>> -	 * created and the ioctls have not had the chance to run.
>> -	 */
>> -	handle = kfd_process_device_create_obj_handle(pdd, mem);
>> -
>> -	if (handle < 0) {
>> -		err = handle;
>> -		goto free_gpuvm;
>> -	}
>> -
>>  	if (kptr) {
>>  		err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(kdev-
>>kgd,
>> -				(struct kgd_mem *)mem, kptr, NULL);
>> +				(struct kgd_mem *)*mem, kptr, NULL);
>>  		if (err) {
>>  			pr_debug("Map GTT BO to kernel failed\n");
>> -			goto free_obj_handle;
>> +			goto sync_memory_failed;
>>  		}
>>  	}
>>
>>  	return err;
>>
>> -free_obj_handle:
>> -	kfd_process_device_remove_obj_handle(pdd, handle);
>> -free_gpuvm:
>>  sync_memory_failed:
>> -	kfd_process_free_gpuvm(mem, pdd);
>> -	return err;
>> +	amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(kdev->kgd,
>*mem,
>> +pdd->drm_priv);
>>
>>  err_map_mem:
>> -	amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, mem,
>pdd->drm_priv,
>> +	amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, *mem,
>> +pdd->drm_priv,
>>  					       NULL);
>>  err_alloc_mem:
>> +	*mem = NULL;
>>  	*kptr = NULL;
>>  	return err;
>>  }
>> @@ -776,6 +766,7 @@ static int
>kfd_process_device_reserve_ib_mem(struct kfd_process_device *pdd)
>>  			KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE |
>>  			KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE |
>>  			KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE;
>> +	struct kgd_mem *mem;
>>  	void *kaddr;
>>  	int ret;
>>
>> @@ -784,15 +775,26 @@ static int
>> kfd_process_device_reserve_ib_mem(struct kfd_process_device *pdd)
>>
>>  	/* ib_base is only set for dGPU */
>>  	ret = kfd_process_alloc_gpuvm(pdd, qpd->ib_base, PAGE_SIZE, flags,
>> -				      &kaddr);
>> +				      &mem, &kaddr);
>>  	if (ret)
>>  		return ret;
>>
>> +	qpd->ib_mem = mem;
>>  	qpd->ib_kaddr = kaddr;
>>
>>  	return 0;
>>  }
>>
>> +static void kfd_process_device_destroy_ib_mem(struct
>> +kfd_process_device *pdd) {
>> +	struct qcm_process_device *qpd = &pdd->qpd;
>> +
>> +	if (!qpd->ib_kaddr || !qpd->ib_base)
>> +		return;
>> +
>> +	kfd_process_free_gpuvm(qpd->ib_mem, pdd, qpd->ib_kaddr); }
>> +
>>  struct kfd_process *kfd_create_process(struct file *filep)  {
>>  	struct kfd_process *process;
>> @@ -947,6 +949,52 @@ static void kfd_process_device_free_bos(struct
>kfd_process_device *pdd)
>>  	}
>>  }
>>
>> +static void kfd_process_free_signal_bo(struct kfd_process *p) {
>> +	struct kfd_process_device *pdd;
>> +	struct kfd_dev *kdev;
>> +	void *mem;
>> +	int i;
>> +
>> +	kdev = kfd_device_by_id(GET_GPU_ID(p->signal_handle));
>> +	if (!kdev)
>> +		return;
>> +
>> +	mutex_lock(&p->mutex);
>> +
>> +	pdd = kfd_get_process_device_data(kdev, p);
>> +	if (!pdd) {
>> +		mutex_unlock(&p->mutex);
>> +		return;
>> +	}
>> +
>> +	mem = kfd_process_device_translate_handle(
>> +		pdd, GET_IDR_HANDLE(p->signal_handle));
>> +	if (!mem) {
>> +		mutex_unlock(&p->mutex);
>> +		return;
>> +	}
>> +
>> +	mutex_unlock(&p->mutex);
>> +
>> +	for (i = 0; i < p->n_pdds; i++) {
>> +		struct kfd_process_device *peer_pdd = p->pdds[i];
>> +
>> +		if (!peer_pdd->drm_priv)
>> +			continue;
>> +		amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
>> +				peer_pdd->dev->kgd, mem, peer_pdd-
>>drm_priv);
>> +	}
>> +
>> +	amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(kdev->kgd,
>mem);
>
>I think you only need to do the kunmap here. You can leave
>"unmap_memory_from_gpu" and "free_memory_of_gpu" and
>"remove_obj_handle"
>to be done in the regular kfd_process_free_outstanding_kfd_bos to avoid
>duplicating that code.

Good idea. Will just kunmap it here. 
>
>> +
>> +	amdgpu_amdkfd_gpuvm_free_memory_of_gpu(kdev->kgd, mem,
>> +		pdd->drm_priv, NULL);
>> +
>> +	kfd_process_device_remove_obj_handle(pdd,
>> +		GET_IDR_HANDLE(p->signal_handle));
>> +}
>> +
>>  static void kfd_process_free_outstanding_kfd_bos(struct kfd_process
>> *p)  {
>>  	int i;
>> @@ -965,6 +1013,9 @@ static void kfd_process_destroy_pdds(struct
>kfd_process *p)
>>  		pr_debug("Releasing pdd (topology id %d) for process (pasid
>0x%x)\n",
>>  				pdd->dev->id, p->pasid);
>>
>> +		kfd_process_device_destroy_cwsr_dgpu(pdd);
>> +		kfd_process_device_destroy_ib_mem(pdd);
>> +
>>  		if (pdd->drm_file) {
>>  			amdgpu_amdkfd_gpuvm_release_process_vm(
>>  					pdd->dev->kgd, pdd->drm_priv);
>> @@ -1049,9 +1100,11 @@ static void kfd_process_wq_release(struct
>> work_struct *work)  {
>>  	struct kfd_process *p = container_of(work, struct kfd_process,
>>  					     release_work);
>> +
>>  	kfd_process_remove_sysfs(p);
>>  	kfd_iommu_unbind_process(p);
>>
>> +	kfd_process_free_signal_bo(p);
>>  	kfd_process_free_outstanding_kfd_bos(p);
>>  	svm_range_list_fini(p);
>>
>> @@ -1066,6 +1119,7 @@ static void kfd_process_wq_release(struct
>work_struct *work)
>>  	put_task_struct(p->lead_thread);
>>
>>  	kfree(p);
>> +
>
>Unnecessary, trailing whitespace.

Will remove it.

Regards,
Lang

>
>Regards,
>  Felix
>
>
>>  }
>>
>>  static void kfd_process_ref_release(struct kref *ref) @@ -1198,6
>> +1252,7 @@ static int kfd_process_device_init_cwsr_dgpu(struct
>kfd_process_device *pdd)
>>  	uint32_t flags = KFD_IOC_ALLOC_MEM_FLAGS_GTT
>>  			| KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE
>>  			| KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE;
>> +	struct kgd_mem *mem;
>>  	void *kaddr;
>>  	int ret;
>>
>> @@ -1206,10 +1261,11 @@ static int
>> kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd)
>>
>>  	/* cwsr_base is only set for dGPU */
>>  	ret = kfd_process_alloc_gpuvm(pdd, qpd->cwsr_base,
>> -				      KFD_CWSR_TBA_TMA_SIZE, flags, &kaddr);
>> +				      KFD_CWSR_TBA_TMA_SIZE, flags, &mem,
>&kaddr);
>>  	if (ret)
>>  		return ret;
>>
>> +	qpd->cwsr_mem = mem;
>>  	qpd->cwsr_kaddr = kaddr;
>>  	qpd->tba_addr = qpd->cwsr_base;
>>
>> @@ -1222,6 +1278,17 @@ static int
>kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd)
>>  	return 0;
>>  }
>>
>> +static void kfd_process_device_destroy_cwsr_dgpu(struct
>> +kfd_process_device *pdd) {
>> +	struct kfd_dev *dev = pdd->dev;
>> +	struct qcm_process_device *qpd = &pdd->qpd;
>> +
>> +	if (!dev->cwsr_enabled || !qpd->cwsr_kaddr || !qpd->cwsr_base)
>> +		return;
>> +
>> +	kfd_process_free_gpuvm(qpd->cwsr_mem, pdd, qpd->cwsr_kaddr); }
>> +
>>  void kfd_process_set_trap_handler(struct qcm_process_device *qpd,
>>  				  uint64_t tba_addr,
>>  				  uint64_t tma_addr)


More information about the amd-gfx mailing list