Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Lizhi Hou <lizhi.hou@amd.com>
Link: https://lore.kernel.org/r/20251016203016.819441-1-lizhi.hou@amd.com

Lizhi Hou 7ea04683 fb4f1cb3

+226 -14
-1
drivers/accel/amdxdna/TODO
··· 1 1 - Add debugfs support 2 - - Add debug BO support
+109 -7
drivers/accel/amdxdna/aie2_ctx.c
··· 226 226 } 227 227 228 228 static int 229 - aie2_sched_nocmd_resp_handler(void *handle, void __iomem *data, size_t size) 229 + aie2_sched_drvcmd_resp_handler(void *handle, void __iomem *data, size_t size) 230 230 { 231 231 struct amdxdna_sched_job *job = handle; 232 232 int ret = 0; 233 - u32 status; 234 233 235 234 if (unlikely(!data)) 236 235 goto out; ··· 239 240 goto out; 240 241 } 241 242 242 - status = readl(data); 243 - XDNA_DBG(job->hwctx->client->xdna, "Resp status 0x%x", status); 243 + job->drv_cmd->result = readl(data); 244 244 245 245 out: 246 246 aie2_sched_notify(job); ··· 312 314 kref_get(&job->refcnt); 313 315 fence = dma_fence_get(job->fence); 314 316 315 - if (unlikely(!cmd_abo)) { 316 - ret = aie2_sync_bo(hwctx, job, aie2_sched_nocmd_resp_handler); 317 + if (job->drv_cmd) { 318 + switch (job->drv_cmd->opcode) { 319 + case SYNC_DEBUG_BO: 320 + ret = aie2_sync_bo(hwctx, job, aie2_sched_drvcmd_resp_handler); 321 + break; 322 + case ATTACH_DEBUG_BO: 323 + ret = aie2_config_debug_bo(hwctx, job, aie2_sched_drvcmd_resp_handler); 324 + break; 325 + default: 326 + ret = -EINVAL; 327 + break; 328 + } 317 329 goto out; 318 330 } 319 331 ··· 774 766 return ret; 775 767 } 776 768 769 + static void aie2_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq) 770 + { 771 + struct dma_fence *out_fence = aie2_cmd_get_out_fence(hwctx, seq); 772 + 773 + if (!out_fence) { 774 + XDNA_ERR(hwctx->client->xdna, "Failed to get fence"); 775 + return; 776 + } 777 + 778 + dma_fence_wait_timeout(out_fence, false, MAX_SCHEDULE_TIMEOUT); 779 + dma_fence_put(out_fence); 780 + } 781 + 782 + static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl, 783 + bool attach) 784 + { 785 + struct amdxdna_client *client = hwctx->client; 786 + struct amdxdna_dev *xdna = client->xdna; 787 + struct amdxdna_drv_cmd cmd = { 0 }; 788 + struct amdxdna_gem_obj *abo; 789 + u64 seq; 790 + int ret; 791 + 792 + abo = amdxdna_gem_get_obj(client, bo_hdl, AMDXDNA_BO_DEV); 793 + if (!abo) { 794 + XDNA_ERR(xdna, "Get bo %d failed", bo_hdl); 795 + return -EINVAL; 796 + } 797 + 798 + if (attach) { 799 + if (abo->assigned_hwctx != AMDXDNA_INVALID_CTX_HANDLE) { 800 + ret = -EBUSY; 801 + goto put_obj; 802 + } 803 + cmd.opcode = ATTACH_DEBUG_BO; 804 + } else { 805 + if (abo->assigned_hwctx != hwctx->id) { 806 + ret = -EINVAL; 807 + goto put_obj; 808 + } 809 + cmd.opcode = DETACH_DEBUG_BO; 810 + } 811 + 812 + ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE, 813 + &bo_hdl, 1, hwctx->id, &seq); 814 + if (ret) { 815 + XDNA_ERR(xdna, "Submit command failed"); 816 + goto put_obj; 817 + } 818 + 819 + aie2_cmd_wait(hwctx, seq); 820 + if (cmd.result) { 821 + XDNA_ERR(xdna, "Response failure 0x%x", cmd.result); 822 + goto put_obj; 823 + } 824 + 825 + if (attach) 826 + abo->assigned_hwctx = hwctx->id; 827 + else 828 + abo->assigned_hwctx = AMDXDNA_INVALID_CTX_HANDLE; 829 + 830 + XDNA_DBG(xdna, "Config debug BO %d to %s", bo_hdl, hwctx->name); 831 + 832 + put_obj: 833 + amdxdna_gem_put_obj(abo); 834 + return ret; 835 + } 836 + 777 837 int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size) 778 838 { 779 839 struct amdxdna_dev *xdna = hwctx->client->xdna; ··· 851 775 case DRM_AMDXDNA_HWCTX_CONFIG_CU: 852 776 return aie2_hwctx_cu_config(hwctx, buf, size); 853 777 case DRM_AMDXDNA_HWCTX_ASSIGN_DBG_BUF: 778 + return aie2_hwctx_cfg_debug_bo(hwctx, (u32)value, true); 854 779 case DRM_AMDXDNA_HWCTX_REMOVE_DBG_BUF: 855 - return -EOPNOTSUPP; 780 + return aie2_hwctx_cfg_debug_bo(hwctx, (u32)value, false); 856 781 default: 857 782 XDNA_DBG(xdna, "Not supported type %d", type); 858 783 return -EOPNOTSUPP; 859 784 } 785 + } 786 + 787 + int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl) 788 + { 789 + struct amdxdna_client *client = hwctx->client; 790 + struct amdxdna_dev *xdna = client->xdna; 791 + struct amdxdna_drv_cmd cmd = { 0 }; 792 + u64 seq; 793 + int ret; 794 + 795 + cmd.opcode = SYNC_DEBUG_BO; 796 + ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE, 797 + &debug_bo_hdl, 1, hwctx->id, &seq); 798 + if (ret) { 799 + XDNA_ERR(xdna, "Submit command failed"); 800 + return ret; 801 + } 802 + 803 + aie2_cmd_wait(hwctx, seq); 804 + if (cmd.result) { 805 + XDNA_ERR(xdna, "Response failure 0x%x", cmd.result); 806 + return ret; 807 + } 808 + 809 + return 0; 860 810 } 861 811 862 812 static int aie2_populate_range(struct amdxdna_gem_obj *abo)
+30 -1
drivers/accel/amdxdna/aie2_message.c
··· 749 749 int ret = 0; 750 750 751 751 req.src_addr = 0; 752 - req.dst_addr = abo->mem.dev_addr - hwctx->client->dev_heap->mem.dev_addr; 752 + req.dst_addr = amdxdna_dev_bo_offset(abo); 753 753 req.size = abo->mem.size; 754 754 755 755 /* Device to Host */ ··· 772 772 } 773 773 774 774 return 0; 775 + } 776 + 777 + int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, 778 + int (*notify_cb)(void *, void __iomem *, size_t)) 779 + { 780 + struct mailbox_channel *chann = hwctx->priv->mbox_chann; 781 + struct amdxdna_gem_obj *abo = to_xdna_obj(job->bos[0]); 782 + struct amdxdna_dev *xdna = hwctx->client->xdna; 783 + struct config_debug_bo_req req; 784 + struct xdna_mailbox_msg msg; 785 + 786 + if (job->drv_cmd->opcode == ATTACH_DEBUG_BO) 787 + req.config = DEBUG_BO_REGISTER; 788 + else 789 + req.config = DEBUG_BO_UNREGISTER; 790 + 791 + req.offset = amdxdna_dev_bo_offset(abo); 792 + req.size = abo->mem.size; 793 + 794 + XDNA_DBG(xdna, "offset 0x%llx size 0x%llx config %d", 795 + req.offset, req.size, req.config); 796 + 797 + msg.handle = job; 798 + msg.notify_cb = notify_cb; 799 + msg.send_data = (u8 *)&req; 800 + msg.send_size = sizeof(req); 801 + msg.opcode = MSG_OP_CONFIG_DEBUG_BO; 802 + 803 + return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT); 775 804 }
+18
drivers/accel/amdxdna/aie2_msg_priv.h
··· 18 18 MSG_OP_CONFIG_CU = 0x11, 19 19 MSG_OP_CHAIN_EXEC_BUFFER_CF = 0x12, 20 20 MSG_OP_CHAIN_EXEC_DPU = 0x13, 21 + MSG_OP_CONFIG_DEBUG_BO = 0x14, 21 22 MSG_OP_MAX_XRT_OPCODE, 22 23 MSG_OP_SUSPEND = 0x101, 23 24 MSG_OP_RESUME = 0x102, ··· 364 363 } __packed; 365 364 366 365 struct sync_bo_resp { 366 + enum aie2_msg_status status; 367 + } __packed; 368 + 369 + #define DEBUG_BO_UNREGISTER 0 370 + #define DEBUG_BO_REGISTER 1 371 + struct config_debug_bo_req { 372 + __u64 offset; 373 + __u64 size; 374 + /* 375 + * config operations. 376 + * DEBUG_BO_REGISTER: Register debug buffer 377 + * DEBUG_BO_UNREGISTER: Unregister debug buffer 378 + */ 379 + __u32 config; 380 + } __packed; 381 + 382 + struct config_debug_bo_resp { 367 383 enum aie2_msg_status status; 368 384 } __packed; 369 385 #endif /* _AIE2_MSG_PRIV_H_ */
+1
drivers/accel/amdxdna/aie2_pci.c
··· 1004 1004 .hwctx_init = aie2_hwctx_init, 1005 1005 .hwctx_fini = aie2_hwctx_fini, 1006 1006 .hwctx_config = aie2_hwctx_config, 1007 + .hwctx_sync_debug_bo = aie2_hwctx_sync_debug_bo, 1007 1008 .cmd_submit = aie2_cmd_submit, 1008 1009 .hmm_invalidate = aie2_hmm_invalidate, 1009 1010 .get_array = aie2_get_array,
+3
drivers/accel/amdxdna/aie2_pci.h
··· 287 287 int (*notify_cb)(void *, void __iomem *, size_t)); 288 288 int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, 289 289 int (*notify_cb)(void *, void __iomem *, size_t)); 290 + int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, 291 + int (*notify_cb)(void *, void __iomem *, size_t)); 290 292 291 293 /* aie2_hwctx.c */ 292 294 int aie2_hwctx_init(struct amdxdna_hwctx *hwctx); 293 295 void aie2_hwctx_fini(struct amdxdna_hwctx *hwctx); 294 296 int aie2_hwctx_config(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size); 297 + int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl); 295 298 void aie2_hwctx_suspend(struct amdxdna_client *client); 296 299 int aie2_hwctx_resume(struct amdxdna_client *client); 297 300 int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq);
+36 -3
drivers/accel/amdxdna/amdxdna_ctx.c
··· 328 328 return ret; 329 329 } 330 330 331 + int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl) 332 + { 333 + struct amdxdna_dev *xdna = client->xdna; 334 + struct amdxdna_hwctx *hwctx; 335 + struct amdxdna_gem_obj *abo; 336 + struct drm_gem_object *gobj; 337 + int ret, idx; 338 + 339 + if (!xdna->dev_info->ops->hwctx_sync_debug_bo) 340 + return -EOPNOTSUPP; 341 + 342 + gobj = drm_gem_object_lookup(client->filp, debug_bo_hdl); 343 + if (!gobj) 344 + return -EINVAL; 345 + 346 + abo = to_xdna_obj(gobj); 347 + guard(mutex)(&xdna->dev_lock); 348 + idx = srcu_read_lock(&client->hwctx_srcu); 349 + hwctx = xa_load(&client->hwctx_xa, abo->assigned_hwctx); 350 + if (!hwctx) { 351 + ret = -EINVAL; 352 + goto unlock_srcu; 353 + } 354 + 355 + ret = xdna->dev_info->ops->hwctx_sync_debug_bo(hwctx, debug_bo_hdl); 356 + 357 + unlock_srcu: 358 + srcu_read_unlock(&client->hwctx_srcu, idx); 359 + drm_gem_object_put(gobj); 360 + return ret; 361 + } 362 + 331 363 static void 332 364 amdxdna_arg_bos_put(struct amdxdna_sched_job *job) 333 365 { ··· 425 393 } 426 394 427 395 int amdxdna_cmd_submit(struct amdxdna_client *client, 396 + struct amdxdna_drv_cmd *drv_cmd, 428 397 u32 cmd_bo_hdl, u32 *arg_bo_hdls, u32 arg_bo_cnt, 429 398 u32 hwctx_hdl, u64 *seq) 430 399 { ··· 439 406 if (!job) 440 407 return -ENOMEM; 441 408 409 + job->drv_cmd = drv_cmd; 410 + 442 411 if (cmd_bo_hdl != AMDXDNA_INVALID_BO_HANDLE) { 443 412 job->cmd_bo = amdxdna_gem_get_obj(client, cmd_bo_hdl, AMDXDNA_BO_CMD); 444 413 if (!job->cmd_bo) { ··· 448 413 ret = -EINVAL; 449 414 goto free_job; 450 415 } 451 - } else { 452 - job->cmd_bo = NULL; 453 416 } 454 417 455 418 ret = amdxdna_arg_bos_lookup(client, job, arg_bo_hdls, arg_bo_cnt); ··· 541 508 } 542 509 } 543 510 544 - ret = amdxdna_cmd_submit(client, cmd_bo_hdl, arg_bo_hdls, 511 + ret = amdxdna_cmd_submit(client, NULL, cmd_bo_hdl, arg_bo_hdls, 545 512 args->arg_count, args->hwctx, &args->seq); 546 513 if (ret) 547 514 XDNA_DBG(xdna, "Submit cmds failed, ret %d", ret);
+15 -1
drivers/accel/amdxdna/amdxdna_ctx.h
··· 95 95 #define drm_job_to_xdna_job(j) \ 96 96 container_of(j, struct amdxdna_sched_job, base) 97 97 98 + enum amdxdna_job_opcode { 99 + SYNC_DEBUG_BO, 100 + ATTACH_DEBUG_BO, 101 + DETACH_DEBUG_BO, 102 + }; 103 + 104 + struct amdxdna_drv_cmd { 105 + enum amdxdna_job_opcode opcode; 106 + u32 result; 107 + }; 108 + 98 109 struct amdxdna_sched_job { 99 110 struct drm_sched_job base; 100 111 struct kref refcnt; ··· 117 106 struct dma_fence *out_fence; 118 107 bool job_done; 119 108 u64 seq; 109 + struct amdxdna_drv_cmd *drv_cmd; 120 110 struct amdxdna_gem_obj *cmd_bo; 121 111 size_t bo_cnt; 122 112 struct drm_gem_object *bos[] __counted_by(bo_cnt); ··· 155 143 void amdxdna_hwctx_remove_all(struct amdxdna_client *client); 156 144 int amdxdna_hwctx_walk(struct amdxdna_client *client, void *arg, 157 145 int (*walk)(struct amdxdna_hwctx *hwctx, void *arg)); 146 + int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl); 158 147 159 148 int amdxdna_cmd_submit(struct amdxdna_client *client, 160 - u32 cmd_bo_hdls, u32 *arg_bo_hdls, u32 arg_bo_cnt, 149 + struct amdxdna_drv_cmd *drv_cmd, u32 cmd_bo_hdls, 150 + u32 *arg_bo_hdls, u32 arg_bo_cnt, 161 151 u32 hwctx_hdl, u64 *seq); 162 152 163 153 int amdxdna_cmd_wait(struct amdxdna_client *client, u32 hwctx_hdl,
+3
drivers/accel/amdxdna/amdxdna_gem.c
··· 962 962 XDNA_DBG(xdna, "Sync bo %d offset 0x%llx, size 0x%llx\n", 963 963 args->handle, args->offset, args->size); 964 964 965 + if (args->direction == SYNC_DIRECT_FROM_DEVICE) 966 + ret = amdxdna_hwctx_sync_debug_bo(abo->client, args->handle); 967 + 965 968 put_obj: 966 969 drm_gem_object_put(gobj); 967 970 return ret;
+6
drivers/accel/amdxdna/amdxdna_gem.h
··· 7 7 #define _AMDXDNA_GEM_H_ 8 8 9 9 #include <linux/hmm.h> 10 + #include "amdxdna_pci_drv.h" 10 11 11 12 struct amdxdna_umap { 12 13 struct vm_area_struct *vma; ··· 61 60 static inline void amdxdna_gem_put_obj(struct amdxdna_gem_obj *abo) 62 61 { 63 62 drm_gem_object_put(to_gobj(abo)); 63 + } 64 + 65 + static inline u64 amdxdna_dev_bo_offset(struct amdxdna_gem_obj *abo) 66 + { 67 + return abo->mem.dev_addr - abo->client->dev_heap->mem.dev_addr; 64 68 } 65 69 66 70 void amdxdna_umap_put(struct amdxdna_umap *mapp);
+2 -1
drivers/accel/amdxdna/amdxdna_pci_drv.c
··· 28 28 * 0.0: Initial version 29 29 * 0.1: Support getting all hardware contexts by DRM_IOCTL_AMDXDNA_GET_ARRAY 30 30 * 0.2: Support getting last error hardware error 31 + * 0.3: Support firmware debug buffer 31 32 */ 32 33 #define AMDXDNA_DRIVER_MAJOR 0 33 - #define AMDXDNA_DRIVER_MINOR 2 34 + #define AMDXDNA_DRIVER_MINOR 3 34 35 35 36 /* 36 37 * Bind the driver base on (vendor_id, device_id) pair and later use the
+1
drivers/accel/amdxdna/amdxdna_pci_drv.h
··· 55 55 int (*hwctx_init)(struct amdxdna_hwctx *hwctx); 56 56 void (*hwctx_fini)(struct amdxdna_hwctx *hwctx); 57 57 int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size); 58 + int (*hwctx_sync_debug_bo)(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl); 58 59 void (*hmm_invalidate)(struct amdxdna_gem_obj *abo, unsigned long cur_seq); 59 60 int (*cmd_submit)(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq); 60 61 int (*get_aie_info)(struct amdxdna_client *client, struct amdxdna_drm_get_info *args);
+1
drivers/accel/amdxdna/npu1_regs.c
··· 46 46 47 47 const struct rt_config npu1_default_rt_cfg[] = { 48 48 { 2, 1, AIE2_RT_CFG_INIT }, /* PDI APP LOAD MODE */ 49 + { 4, 1, AIE2_RT_CFG_INIT }, /* Debug BO */ 49 50 { 1, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */ 50 51 { 0 }, 51 52 };
+1
drivers/accel/amdxdna/npu4_regs.c
··· 63 63 64 64 const struct rt_config npu4_default_rt_cfg[] = { 65 65 { 5, 1, AIE2_RT_CFG_INIT }, /* PDI APP LOAD MODE */ 66 + { 10, 1, AIE2_RT_CFG_INIT }, /* DEBUG BUF */ 66 67 { 1, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */ 67 68 { 2, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */ 68 69 { 3, 1, AIE2_RT_CFG_CLK_GATING }, /* Clock gating on */