Allow us to bind a PASID to the current process and unbind it when the VM isn't used any more. Signed-off-by: Christian König <christian.koenig at amd.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 28 ++++++++++++++++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index c13cf7e79b2e..8cfdb07a4439 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -24,6 +24,7 @@ #include <linux/idr.h> #include <linux/dma-fence-array.h> +#include <linux/amd-iommu.h> #include <drm/drmP.h> #include "amdgpu.h" @@ -43,6 +44,7 @@ static DEFINE_IDA(amdgpu_pasid_ida); /* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb { struct dma_fence_cb cb; + struct pci_dev *pdev; unsigned int pasid; }; @@ -85,12 +87,30 @@ void amdgpu_pasid_free(unsigned int pasid) ida_simple_remove(&amdgpu_pasid_ida, pasid); } +int amdgpu_pasid_bind(struct pci_dev *pdev, unsigned int pasid) +{ +#ifdef CONFIG_DRM_AMDGPU_ATC + return amd_iommu_bind_pasid(pdev, pasid, current); +#else + return -ENODEV; +#endif +} + +void amdgpu_pasid_unbind(struct pci_dev *pdev, unsigned int pasid) +{ +#ifdef CONFIG_DRM_AMDGPU_ATC + if (pdev) + amd_iommu_unbind_pasid(pdev, pasid); +#endif +} + static void amdgpu_pasid_free_cb(struct dma_fence *fence, struct dma_fence_cb *_cb) { struct amdgpu_pasid_cb *cb = container_of(_cb, struct amdgpu_pasid_cb, cb); + amdgpu_pasid_unbind(cb->pdev, cb->pasid); amdgpu_pasid_free(cb->pasid); dma_fence_put(fence); kfree(cb); @@ -100,11 +120,13 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence, * amdgpu_pasid_free_delayed - free pasid when fences signal * * @resv: reservation object with the fences to wait for + * @pdev: optional pci device to unbind the PASID from * @pasid: pasid to free * * Free the pasid only after all the fences in resv are signaled. */ void amdgpu_pasid_free_delayed(struct reservation_object *resv, + struct pci_dev *pdev, unsigned int pasid) { struct dma_fence *fence, **fences; @@ -117,6 +139,7 @@ void amdgpu_pasid_free_delayed(struct reservation_object *resv, goto fallback; if (count == 0) { + amdgpu_pasid_unbind(pdev, pasid); amdgpu_pasid_free(pasid); return; } @@ -140,10 +163,10 @@ void amdgpu_pasid_free_delayed(struct reservation_object *resv, cb = kmalloc(sizeof(*cb), GFP_KERNEL); if (!cb) { /* Last resort when we are OOM */ - dma_fence_wait(fence, false); dma_fence_put(fence); - amdgpu_pasid_free(pasid); + goto fallback; } else { + cb->pdev = pdev; cb->pasid = pasid; if (dma_fence_add_callback(fence, &cb->cb, amdgpu_pasid_free_cb)) @@ -158,6 +181,7 @@ void amdgpu_pasid_free_delayed(struct reservation_object *resv, */ reservation_object_wait_timeout_rcu(resv, true, false, MAX_SCHEDULE_TIMEOUT); + amdgpu_pasid_unbind(pdev, pasid); amdgpu_pasid_free(pasid); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index 38f37c16fc5e..ef88fc4f21fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -69,7 +69,10 @@ struct amdgpu_vmid_mgr { int amdgpu_pasid_alloc(unsigned int bits); void amdgpu_pasid_free(unsigned int pasid); +int amdgpu_pasid_bind(struct pci_dev *pdev, unsigned int pasid); +void amdgpu_pasid_unbind(struct pci_dev *pdev, unsigned int pasid); void amdgpu_pasid_free_delayed(struct reservation_object *resv, + struct pci_dev *pdev, unsigned int pasid); bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 431038885778..b18920007624 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -927,7 +927,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_vm_fini(adev, &fpriv->vm); if (pasid) - amdgpu_pasid_free_delayed(pd->tbo.resv, pasid); + amdgpu_pasid_free_delayed(pd->tbo.resv, NULL, pasid); amdgpu_bo_unref(&pd); idr_for_each_entry(&fpriv->bo_list_handles, list, handle) -- 2.14.1