[PATCH 47/95] drm/amdgpu: Implement UALink handle export
Alex Deucher <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
From: Mukul Joshi <[email protected]> This patch adds the implementation for exporting a ualink handle associated with a BO. If the BO doesn't have a ualink handle generated yet, we first allocate a unique ualink handle, add it to a lookup table and return the handle to user-space. Signed-off-by: Mukul Joshi <[email protected]> Reviewed-by: Felix Kuehling <[email protected]> Signed-off-by: Alex Deucher <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 131 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h | 67 +++++++++++ 2 files changed, 198 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c index 059ba29d9b5cc..34c69de06e48d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c @@ -24,6 +24,7 @@ #include <linux/xarray.h> #include <drm/drm_mm.h> +#include <linux/random.h> #include "amdgpu.h" #include "amdgpu_ualink.h" #include "amdgpu_xgmi.h" @@ -1175,6 +1176,136 @@ static void amdgpu_ualink_npa_mm_fini(struct amdgpu_device *adev) drm_mm_takedown(&adev->ualink.npa_mm.mm); } +/* The caller of this function is expected to hold the XA lock when calling + * this function. + */ +static void amdgpu_generate_ualink_handle(struct amdgpu_device *adev, + struct amdgpu_ualink_handle *handle) +{ + bool unique; + + do { + handle->handle_lo = get_random_u64(); + /* Replace bottom 10 bits in handle_lo with accId */ + handle->handle_lo &= ~AMDGPU_UALINK_HANDLE_ACCID_MASK; + handle->handle_lo |= adev->ualink.info->ppod.accel_id; + + /* Don't generate/store a Handle with value 0. */ + if (!handle->handle_lo) + continue; + + /* Find if the handle already exists in the exporter xarray. + * If it already exists, then regenerate the handle since we + * want the handle to be unique. + */ + unique = !xa_load(&adev->ualink.exp_xa, handle->handle_lo); + } while (!unique); + + handle->handle_hi = get_random_u64(); + dev_dbg(adev->dev, "GENERATE-HANDLE: generated handle: %llx:%llx\n", + handle->handle_hi, handle->handle_lo); +} + +static void amdgpu_ualink_exp_cleanup_worker(struct work_struct *work) +{ +} + +int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp, + u32 gem_handle, + struct amdgpu_ualink_handle *handle_out) +{ + struct amdgpu_ualink_exp_xa_node *exp_xa_node; + struct amdgpu_ualink_handle handle; + struct drm_gem_object *gobj; + struct amdgpu_device *adev; + struct amdgpu_bo *robj; + int r = 0, i; + + gobj = drm_gem_object_lookup(filp, gem_handle); + if (!gobj) + return -ENOENT; + + robj = gem_to_amdgpu_bo(gobj); + adev = amdgpu_ttm_adev(robj->tbo.bdev); + + if (!(robj->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM)) { + dev_err(adev->dev, "Only VRAM BOs can be exported\n"); + r = -EOPNOTSUPP; + goto out; + } + + if (!robj->ualink_handle_lo) { + /* If no ualink handle generated for BO, then generate one and + * add it to the exporter Xarray. + */ + exp_xa_node = kzalloc(sizeof(*exp_xa_node), GFP_KERNEL); + if (!exp_xa_node) { + dev_err(adev->dev, "Failed to allocate exp_xa_node\n"); + r = -ENOMEM; + goto out; + } + + amdgpu_bo_ref(robj); + exp_xa_node->bo = robj; + init_completion(&exp_xa_node->npa_done); + bitmap_zero(exp_xa_node->importers_bitmap, + AMDGPU_UALINK_ACCEL_MAX); + bitmap_zero(exp_xa_node->npa_release_bitmap, + AMDGPU_UALINK_ACCEL_MAX); + kref_init(&exp_xa_node->refcount); + mutex_init(&exp_xa_node->node_lock); + INIT_WORK(&exp_xa_node->cleanup_work, + amdgpu_ualink_exp_cleanup_worker); + for (i = 0; i < AMDGPU_UALINK_ACCEL_MAX; i++) { + INIT_LIST_HEAD(&exp_xa_node->importer_entries[i].list); + exp_xa_node->importer_entries[i].parent = exp_xa_node; + } + /* DMABuf handle for local import of fabric handles */ + exp_xa_node->dmabuf = drm_gem_prime_handle_to_dmabuf(&adev->ddev, filp, + gem_handle, DRM_CLOEXEC | DRM_RDWR); + if (IS_ERR(exp_xa_node->dmabuf)) { + r = PTR_ERR(exp_xa_node->dmabuf); + dev_err(adev->dev, "Failed to generate DMABuf for the BO\n"); + kfree(exp_xa_node); + goto out; + } + + xa_lock(&adev->ualink.exp_xa); + amdgpu_generate_ualink_handle(adev, &handle); + exp_xa_node->handle = handle; + r = __xa_insert(&adev->ualink.exp_xa, handle.handle_lo, + exp_xa_node, GFP_KERNEL); + xa_unlock(&adev->ualink.exp_xa); + if (r) { + dev_err(adev->dev, "Failed to insert exp_xa_node into XA: %d\n", r); + dma_buf_put(exp_xa_node->dmabuf); + amdgpu_bo_unref(&robj); + kfree(exp_xa_node); + goto out; + } + + robj->ualink_handle_lo = handle.handle_lo; + /* Return the generated handle back to the caller */ + *handle_out = handle; + } else { + handle_out->handle_lo = robj->ualink_handle_lo; + + /* Do a sanity check to ensure the handle exists in the XA */ + xa_lock(&adev->ualink.exp_xa); + exp_xa_node = xa_load(&adev->ualink.exp_xa, + robj->ualink_handle_lo); + xa_unlock(&adev->ualink.exp_xa); + WARN(!exp_xa_node, "Exp XA: Handle_Lo: %llx not found", + robj->ualink_handle_lo); + if (exp_xa_node) + handle_out->handle_hi = exp_xa_node->handle.handle_hi; + } + +out: + drm_gem_object_put(gobj); + return r; +} + int amdgpu_ualink_manager_start(struct amdgpu_device *adev) { int i, r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h index 333de2058f5b4..cf9522e4f8a74 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.h @@ -31,6 +31,8 @@ #define AMDGPU_UALINK_LOCAL_ACCELS_MAX 8 #define AMDGPU_UALINK_STATIONS_MAX 64 +#define AMDGPU_UALINK_HANDLE_ACCID_MASK GENMASK_ULL(9, 0) + enum amdgpu_ualink_conn_state { AMDGPU_UALINK_CONN_NOT_READY = 0, AMDGPU_UALINK_CONN_IN_PROGRESS = 1, @@ -121,6 +123,16 @@ struct amdgpu_ualink_station_config { }; #define to_ualink_station_config(ko) container_of(ko, struct amdgpu_ualink_station_config, kobj) +struct amdgpu_ualink_handle { + union { + struct { + u64 handle_lo; + u64 handle_hi; + }; + u64 handle[2]; + }; +}; + struct amdgpu_ualink_npa_mm { struct drm_mm mm; u64 va_start; @@ -128,6 +140,58 @@ struct amdgpu_ualink_npa_mm { struct mutex mm_lock; }; +struct amdgpu_ualink_importer_entry { + struct drm_mm_node *mm_node; + u64 npa_addr; + + /* Keep track of if the connection got reset */ + u32 generation_count; + + /* Used to connect all handles exported to a particular importer */ + struct list_head list; + + /* Pointer to the parent XA node. */ + struct amdgpu_ualink_exp_xa_node *parent; +}; + +struct amdgpu_ualink_exp_xa_node { + /* 128-bit handle for the BO */ + struct amdgpu_ualink_handle handle; + + /* Pointer to the BO thats exported.*/ + struct amdgpu_bo *bo; + + /* Dmabuf corresponding to the BO */ + struct dma_buf *dmabuf; + + /* Mutex to protect the node from concurrent access */ + struct mutex node_lock; + + /* Used for storing importer info in source identification mode */ + struct amdgpu_ualink_importer_entry importer_entries[AMDGPU_UALINK_ACCEL_MAX]; + + /* Used to track all importers of this BO. This is set when the + * exporter sends back the NPA-RSP message. + */ + DECLARE_BITMAP(importers_bitmap, AMDGPU_UALINK_ACCEL_MAX); + + /* This bitmap is used to send NPA-REVOKE messages to all the importers. + * And to track the NPA-RELEASE response for each NPA-REVOKE message sent. + * A bit is cleared in this bitmap when the NPA RELEASE message is + * received in response to the NPA-REVOKE message. + */ + DECLARE_BITMAP(npa_release_bitmap, AMDGPU_UALINK_ACCEL_MAX); + + /* Use to signal responses received from all importers */ + struct completion npa_done; + + /* Refcount to track lifetime of this node */ + struct kref refcount; + + /* Work to cleanup the node. */ + struct work_struct cleanup_work; +}; + struct amdgpu_ualink_connection { struct completion hello_done; struct mutex lock; @@ -199,4 +263,7 @@ int amdgpu_ualink_init(struct amdgpu_device *adev); void amdgpu_ualink_fini(struct amdgpu_device *adev); int amdgpu_ualink_manager_start(struct amdgpu_device *adev); void amdgpu_ualink_manager_stop(struct amdgpu_device *adev); +int amdgpu_ualink_export_handle(struct drm_device *dev, struct drm_file *filp, + u32 gem_handle, + struct amdgpu_ualink_handle *handle_out); #endif -- 2.55.0