[PATCH V3 11/11] accel/amdxdna: Add firmware debug buffer support

From: Lizhi Hou
Date: Wed Sep 11 2024 - 14:08:16 EST


User application may allocate a debug buffer and attach it to an NPU
context through the driver. Then the NPU firmware prints its debug
information to this buffer for debugging.

Co-developed-by: Min Ma <min.ma@xxxxxxx>
Signed-off-by: Min Ma <min.ma@xxxxxxx>
Signed-off-by: Lizhi Hou <lizhi.hou@xxxxxxx>
---
drivers/accel/amdxdna/aie2_ctx.c | 45 +++++++++++++++-
drivers/accel/amdxdna/amdxdna_ctx.c | 1 +
drivers/accel/amdxdna/amdxdna_ctx.h | 1 +
drivers/accel/amdxdna/amdxdna_gem.c | 81 +++++++++++++++++++++++++++++
drivers/accel/amdxdna/amdxdna_gem.h | 4 ++
5 files changed, 131 insertions(+), 1 deletion(-)

diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
index eba37d2dc933..6d35c67b9e47 100644
--- a/drivers/accel/amdxdna/aie2_ctx.c
+++ b/drivers/accel/amdxdna/aie2_ctx.c
@@ -719,6 +719,48 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size
return ret;
}

+static int aie2_hwctx_attach_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl)
+{
+ struct amdxdna_client *client = hwctx->client;
+ struct amdxdna_dev *xdna = client->xdna;
+ struct amdxdna_gem_obj *abo;
+ int ret;
+
+ abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_DEV);
+ if (!abo) {
+ XDNA_ERR(xdna, "Get bo %d failed", bo_hdl);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ ret = amdxdna_gem_set_assigned_hwctx(client, bo_hdl, hwctx->id);
+ if (ret) {
+ XDNA_ERR(xdna, "Failed to attach debug BO %d to %s: %d", bo_hdl, hwctx->name, ret);
+ goto put_obj;
+ }
+ XDNA_DBG(xdna, "Attached debug BO %d to %s", bo_hdl, hwctx->name);
+
+put_obj:
+ amdxdna_gem_put_obj(abo);
+err_out:
+ return ret;
+}
+
+static int aie2_hwctx_detach_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl)
+{
+ struct amdxdna_client *client = hwctx->client;
+ struct amdxdna_dev *xdna = client->xdna;
+
+ if (amdxdna_gem_get_assigned_hwctx(client, bo_hdl) != hwctx->id) {
+ XDNA_ERR(xdna, "Debug BO %d isn't attached to %s", bo_hdl, hwctx->name);
+ return -EINVAL;
+ }
+
+ amdxdna_gem_clear_assigned_hwctx(client, bo_hdl);
+ XDNA_DBG(xdna, "Detached debug BO %d from %s", bo_hdl, hwctx->name);
+ return 0;
+}
+
int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size)
{
struct amdxdna_dev *xdna = hwctx->client->xdna;
@@ -728,8 +770,9 @@ int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *bu
case DRM_AMDXDNA_HWCTX_CONFIG_CU:
return aie2_hwctx_cu_config(hwctx, buf, size);
case DRM_AMDXDNA_HWCTX_ASSIGN_DBG_BUF:
+ return aie2_hwctx_attach_debug_bo(hwctx, (u32)value);
case DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF:
- return -EOPNOTSUPP;
+ return aie2_hwctx_detach_debug_bo(hwctx, (u32)value);
default:
XDNA_DBG(xdna, "Not supported type %d", type);
return -EOPNOTSUPP;
diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c
index f242a92cb9aa..58b8dbbec7ce 100644
--- a/drivers/accel/amdxdna/amdxdna_ctx.c
+++ b/drivers/accel/amdxdna/amdxdna_ctx.c
@@ -194,6 +194,7 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
hwctx->num_tiles = args->num_tiles;
hwctx->mem_size = args->mem_size;
hwctx->max_opc = args->max_opc;
+ hwctx->log_buf_bo = args->log_buf_bo;
mutex_lock(&client->hwctx_lock);
ret = idr_alloc_cyclic(&client->hwctx_idr, hwctx, 0, MAX_HWCTX_ID, GFP_KERNEL);
if (ret < 0) {
diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h
index e035ebd54045..6349819cc959 100644
--- a/drivers/accel/amdxdna/amdxdna_ctx.h
+++ b/drivers/accel/amdxdna/amdxdna_ctx.h
@@ -76,6 +76,7 @@ struct amdxdna_hwctx {
u32 *col_list;
u32 start_col;
u32 num_col;
+ u32 log_buf_bo;
#define HWCTX_STAT_INIT 0
#define HWCTX_STAT_READY 1
#define HWCTX_STAT_STOP 2
diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
index 8d813edf371e..7df11c362a4d 100644
--- a/drivers/accel/amdxdna/amdxdna_gem.c
+++ b/drivers/accel/amdxdna/amdxdna_gem.c
@@ -593,10 +593,12 @@ int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm
int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
void *data, struct drm_file *filp)
{
+ struct amdxdna_client *client = filp->driver_priv;
struct amdxdna_dev *xdna = to_xdna_dev(dev);
struct amdxdna_drm_sync_bo *args = data;
struct amdxdna_gem_obj *abo;
struct drm_gem_object *gobj;
+ u32 hwctx_hdl;
int ret;

gobj = drm_gem_object_lookup(filp, args->handle);
@@ -619,6 +621,28 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,

amdxdna_gem_unpin(abo);

+ if (abo->assigned_hwctx != AMDXDNA_INVALID_CTX_HANDLE &&
+ args->direction == SYNC_DIRECT_FROM_DEVICE) {
+ u64 seq;
+
+ hwctx_hdl = amdxdna_gem_get_assigned_hwctx(client, args->handle);
+ if (hwctx_hdl == AMDXDNA_INVALID_CTX_HANDLE ||
+ args->direction != SYNC_DIRECT_FROM_DEVICE) {
+ XDNA_ERR(xdna, "Sync failed, dir %d", args->direction);
+ ret = -EINVAL;
+ goto put_obj;
+ }
+
+ ret = amdxdna_cmd_submit(client, AMDXDNA_INVALID_BO_HANDLE,
+ &args->handle, 1, hwctx_hdl, &seq);
+ if (ret) {
+ XDNA_ERR(xdna, "Submit command failed");
+ goto put_obj;
+ }
+
+ ret = amdxdna_cmd_wait(client, hwctx_hdl, seq, 3000 /* ms */);
+ }
+
XDNA_DBG(xdna, "Sync bo %d offset 0x%llx, size 0x%llx\n",
args->handle, args->offset, args->size);

@@ -626,3 +650,60 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
drm_gem_object_put(gobj);
return ret;
}
+
+u32 amdxdna_gem_get_assigned_hwctx(struct amdxdna_client *client, u32 bo_hdl)
+{
+ struct amdxdna_gem_obj *abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_INVALID);
+ u32 ctxid;
+
+ if (!abo) {
+ XDNA_DBG(client->xdna, "Get bo %d failed", bo_hdl);
+ return AMDXDNA_INVALID_CTX_HANDLE;
+ }
+
+ mutex_lock(&abo->lock);
+ ctxid = abo->assigned_hwctx;
+ if (!idr_find(&client->hwctx_idr, ctxid))
+ ctxid = AMDXDNA_INVALID_CTX_HANDLE;
+ mutex_unlock(&abo->lock);
+
+ amdxdna_gem_put_obj(abo);
+ return ctxid;
+}
+
+int amdxdna_gem_set_assigned_hwctx(struct amdxdna_client *client, u32 bo_hdl, u32 ctxid)
+{
+ struct amdxdna_gem_obj *abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_INVALID);
+ int ret = 0;
+
+ if (!abo) {
+ XDNA_DBG(client->xdna, "Get bo %d failed", bo_hdl);
+ return -EINVAL;
+ }
+
+ mutex_lock(&abo->lock);
+ if (!idr_find(&client->hwctx_idr, abo->assigned_hwctx))
+ abo->assigned_hwctx = ctxid;
+ else if (ctxid != abo->assigned_hwctx)
+ ret = -EBUSY;
+ mutex_unlock(&abo->lock);
+
+ amdxdna_gem_put_obj(abo);
+ return ret;
+}
+
+void amdxdna_gem_clear_assigned_hwctx(struct amdxdna_client *client, u32 bo_hdl)
+{
+ struct amdxdna_gem_obj *abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_INVALID);
+
+ if (!abo) {
+ XDNA_DBG(client->xdna, "Get bo %d failed", bo_hdl);
+ return;
+ }
+
+ mutex_lock(&abo->lock);
+ abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE;
+ mutex_unlock(&abo->lock);
+
+ amdxdna_gem_put_obj(abo);
+}
diff --git a/drivers/accel/amdxdna/amdxdna_gem.h b/drivers/accel/amdxdna/amdxdna_gem.h
index 8ccc0375dd9d..d7337191d5ea 100644
--- a/drivers/accel/amdxdna/amdxdna_gem.h
+++ b/drivers/accel/amdxdna/amdxdna_gem.h
@@ -58,6 +58,10 @@ int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo);
int amdxdna_gem_pin(struct amdxdna_gem_obj *abo);
void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo);

+u32 amdxdna_gem_get_assigned_hwctx(struct amdxdna_client *client, u32 bo_hdl);
+int amdxdna_gem_set_assigned_hwctx(struct amdxdna_client *client, u32 bo_hdl, u32 ctx_hdl);
+void amdxdna_gem_clear_assigned_hwctx(struct amdxdna_client *client, u32 bo_hdl);
+
int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
--
2.34.1