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 <linux/xarray.h>
|
||||||
#include <drm/drm_mm.h>
|
#include <drm/drm_mm.h>
|
||||||
|
#include <linux/random.h>
|
||||||
#include "amdgpu.h"
|
#include "amdgpu.h"
|
||||||
#include "amdgpu_ualink.h"
|
#include "amdgpu_ualink.h"
|
||||||
#include "amdgpu_xgmi.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);
|
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 amdgpu_ualink_manager_start(struct amdgpu_device *adev)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ struct amdgpu_device;
|
||||||
#define AMDGPU_UALINK_LOCAL_ACCELS_MAX 8
|
#define AMDGPU_UALINK_LOCAL_ACCELS_MAX 8
|
||||||
#define AMDGPU_UALINK_STATIONS_MAX 64
|
#define AMDGPU_UALINK_STATIONS_MAX 64
|
||||||
|
|
||||||
|
#define AMDGPU_UALINK_HANDLE_ACCID_MASK GENMASK_ULL(9, 0)
|
||||||
|
|
||||||
enum amdgpu_ualink_conn_state {
|
enum amdgpu_ualink_conn_state {
|
||||||
AMDGPU_UALINK_CONN_NOT_READY = 0,
|
AMDGPU_UALINK_CONN_NOT_READY = 0,
|
||||||
AMDGPU_UALINK_CONN_IN_PROGRESS = 1,
|
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)
|
#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 amdgpu_ualink_npa_mm {
|
||||||
struct drm_mm mm;
|
struct drm_mm mm;
|
||||||
u64 va_start;
|
u64 va_start;
|
||||||
|
|
@ -132,6 +144,58 @@ struct amdgpu_ualink_npa_mm {
|
||||||
struct mutex mm_lock;
|
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 amdgpu_ualink_connection {
|
||||||
struct completion hello_done;
|
struct completion hello_done;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
|
@ -203,4 +267,7 @@ int amdgpu_ualink_init(struct amdgpu_device *adev);
|
||||||
void amdgpu_ualink_fini(struct amdgpu_device *adev);
|
void amdgpu_ualink_fini(struct amdgpu_device *adev);
|
||||||
int amdgpu_ualink_manager_start(struct amdgpu_device *adev);
|
int amdgpu_ualink_manager_start(struct amdgpu_device *adev);
|
||||||
void amdgpu_ualink_manager_stop(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
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user