Commit 7ea04683 authored by Lizhi Hou's avatar Lizhi Hou
Browse files

accel/amdxdna: Support firmware debug buffer



To collect firmware debug information, the userspace application allocates
a AMDXDNA_BO_DEV buffer object through DRM_IOCTL_AMDXDNA_CREATE_BO.
Then it associates the buffer with the hardware context through
DRM_IOCTL_AMDXDNA_CONFIG_HWCTX which requests firmware to bind the buffer
through a mailbox command. The firmware then writes the debug data into
this buffer. The buffer can be mapped into userspace so that
applications can retrieve and analyze the firmware debug information.

Reviewed-by: default avatarMario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: default avatarLizhi Hou <lizhi.hou@amd.com>
Link: https://lore.kernel.org/r/20251016203016.819441-1-lizhi.hou@amd.com
parent fb4f1cb3
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
- Add debugfs support
- Add debug BO support
+109 −7
Original line number Diff line number Diff line
@@ -226,11 +226,10 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
}

static int
aie2_sched_nocmd_resp_handler(void *handle, void __iomem *data, size_t size)
aie2_sched_drvcmd_resp_handler(void *handle, void __iomem *data, size_t size)
{
	struct amdxdna_sched_job *job = handle;
	int ret = 0;
	u32 status;

	if (unlikely(!data))
		goto out;
@@ -240,8 +239,7 @@ aie2_sched_nocmd_resp_handler(void *handle, void __iomem *data, size_t size)
		goto out;
	}

	status = readl(data);
	XDNA_DBG(job->hwctx->client->xdna, "Resp status 0x%x", status);
	job->drv_cmd->result = readl(data);

out:
	aie2_sched_notify(job);
@@ -314,8 +312,18 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
	kref_get(&job->refcnt);
	fence = dma_fence_get(job->fence);

	if (unlikely(!cmd_abo)) {
		ret = aie2_sync_bo(hwctx, job, aie2_sched_nocmd_resp_handler);
	if (job->drv_cmd) {
		switch (job->drv_cmd->opcode) {
		case SYNC_DEBUG_BO:
			ret = aie2_sync_bo(hwctx, job, aie2_sched_drvcmd_resp_handler);
			break;
		case ATTACH_DEBUG_BO:
			ret = aie2_config_debug_bo(hwctx, job, aie2_sched_drvcmd_resp_handler);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		goto out;
	}

@@ -766,6 +774,74 @@ static int aie2_hwctx_cu_config(struct amdxdna_hwctx *hwctx, void *buf, u32 size
	return ret;
}

static void aie2_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq)
{
	struct dma_fence *out_fence = aie2_cmd_get_out_fence(hwctx, seq);

	if (!out_fence) {
		XDNA_ERR(hwctx->client->xdna, "Failed to get fence");
		return;
	}

	dma_fence_wait_timeout(out_fence, false, MAX_SCHEDULE_TIMEOUT);
	dma_fence_put(out_fence);
}

static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl,
				   bool attach)
{
	struct amdxdna_client *client = hwctx->client;
	struct amdxdna_dev *xdna = client->xdna;
	struct amdxdna_drv_cmd cmd = { 0 };
	struct amdxdna_gem_obj *abo;
	u64 seq;
	int ret;

	abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_DEV);
	if (!abo) {
		XDNA_ERR(xdna, "Get bo %d failed", bo_hdl);
		return -EINVAL;
	}

	if (attach) {
		if (abo->assigned_hwctx != AMDXDNA_INVALID_CTX_HANDLE) {
			ret = -EBUSY;
			goto put_obj;
		}
		cmd.opcode = ATTACH_DEBUG_BO;
	} else {
		if (abo->assigned_hwctx != hwctx->id) {
			ret = -EINVAL;
			goto put_obj;
		}
		cmd.opcode = DETACH_DEBUG_BO;
	}

	ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE,
				 &bo_hdl, 1, hwctx->id, &seq);
	if (ret) {
		XDNA_ERR(xdna, "Submit command failed");
		goto put_obj;
	}

	aie2_cmd_wait(hwctx, seq);
	if (cmd.result) {
		XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
		goto put_obj;
	}

	if (attach)
		abo->assigned_hwctx = hwctx->id;
	else
		abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE;

	XDNA_DBG(xdna, "Config debug BO %d to %s", bo_hdl, hwctx->name);

put_obj:
	amdxdna_gem_put_obj(abo);
	return ret;
}

int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size)
{
	struct amdxdna_dev *xdna = hwctx->client->xdna;
@@ -775,14 +851,40 @@ 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_cfg_debug_bo(hwctx, (u32)value, true);
	case DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF:
		return -EOPNOTSUPP;
		return aie2_hwctx_cfg_debug_bo(hwctx, (u32)value, false);
	default:
		XDNA_DBG(xdna, "Not supported type %d", type);
		return -EOPNOTSUPP;
	}
}

int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl)
{
	struct amdxdna_client *client = hwctx->client;
	struct amdxdna_dev *xdna = client->xdna;
	struct amdxdna_drv_cmd cmd = { 0 };
	u64 seq;
	int ret;

	cmd.opcode = SYNC_DEBUG_BO;
	ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE,
				 &debug_bo_hdl, 1, hwctx->id, &seq);
	if (ret) {
		XDNA_ERR(xdna, "Submit command failed");
		return ret;
	}

	aie2_cmd_wait(hwctx, seq);
	if (cmd.result) {
		XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
		return ret;
	}

	return 0;
}

static int aie2_populate_range(struct amdxdna_gem_obj *abo)
{
	struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
+30 −1
Original line number Diff line number Diff line
@@ -749,7 +749,7 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
	int ret = 0;

	req.src_addr = 0;
	req.dst_addr = abo->mem.dev_addr - hwctx->client->dev_heap->mem.dev_addr;
	req.dst_addr = amdxdna_dev_bo_offset(abo);
	req.size = abo->mem.size;

	/* Device to Host */
@@ -773,3 +773,32 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,

	return 0;
}

int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
			 int (*notify_cb)(void *, void __iomem *, size_t))
{
	struct mailbox_channel *chann = hwctx->priv->mbox_chann;
	struct amdxdna_gem_obj *abo = to_xdna_obj(job->bos[0]);
	struct amdxdna_dev *xdna = hwctx->client->xdna;
	struct config_debug_bo_req req;
	struct xdna_mailbox_msg msg;

	if (job->drv_cmd->opcode == ATTACH_DEBUG_BO)
		req.config = DEBUG_BO_REGISTER;
	else
		req.config = DEBUG_BO_UNREGISTER;

	req.offset = amdxdna_dev_bo_offset(abo);
	req.size = abo->mem.size;

	XDNA_DBG(xdna, "offset 0x%llx size 0x%llx config %d",
		 req.offset, req.size, req.config);

	msg.handle = job;
	msg.notify_cb = notify_cb;
	msg.send_data = (u8 *)&req;
	msg.send_size = sizeof(req);
	msg.opcode = MSG_OP_CONFIG_DEBUG_BO;

	return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
}
+18 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ enum aie2_msg_opcode {
	MSG_OP_CONFIG_CU                   = 0x11,
	MSG_OP_CHAIN_EXEC_BUFFER_CF        = 0x12,
	MSG_OP_CHAIN_EXEC_DPU              = 0x13,
	MSG_OP_CONFIG_DEBUG_BO             = 0x14,
	MSG_OP_MAX_XRT_OPCODE,
	MSG_OP_SUSPEND                     = 0x101,
	MSG_OP_RESUME                      = 0x102,
@@ -365,4 +366,21 @@ struct sync_bo_req {
struct sync_bo_resp {
	enum aie2_msg_status	status;
} __packed;

#define DEBUG_BO_UNREGISTER 0
#define DEBUG_BO_REGISTER   1
struct config_debug_bo_req {
	__u64	offset;
	__u64	size;
	/*
	 * config operations.
	 *   DEBUG_BO_REGISTER: Register debug buffer
	 *   DEBUG_BO_UNREGISTER: Unregister debug buffer
	 */
	__u32	config;
} __packed;

struct config_debug_bo_resp {
	enum aie2_msg_status	status;
} __packed;
#endif /* _AIE2_MSG_PRIV_H_ */
+1 −0
Original line number Diff line number Diff line
@@ -1004,6 +1004,7 @@ const struct amdxdna_dev_ops aie2_ops = {
	.hwctx_init = aie2_hwctx_init,
	.hwctx_fini = aie2_hwctx_fini,
	.hwctx_config = aie2_hwctx_config,
	.hwctx_sync_debug_bo = aie2_hwctx_sync_debug_bo,
	.cmd_submit = aie2_cmd_submit,
	.hmm_invalidate = aie2_hmm_invalidate,
	.get_array = aie2_get_array,
Loading