mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
drm/amdgpu: Implement UALink handle export
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 <mukul.joshi@amd.com> Reviewed-by: Felix Kuehling <felix.kuehling@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
869fdd2445
commit
c67cb19811
|
|
@ -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"
|
||||
|
|
@ -1221,6 +1222,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;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ struct amdgpu_device;
|
|||
#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,
|
||||
|
|
@ -125,6 +127,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;
|
||||
|
|
@ -132,6 +144,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;
|
||||
|
|
@ -203,4 +267,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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user