Add xe_hw_engine_snapshot_from_capture to take snapshot from capture node list. Add data struct to map register to a snapshot field, although all field is mapped now, which means the offset could be optimized, while in the future, depends on system configuration, the field might not be consecutive. This is reserved for future. Signed-off-by: Zhanjun Dong <zhanjun.dong@xxxxxxxxx> --- drivers/gpu/drm/xe/xe_guc_capture.c | 99 ++++++++++++++++++++++- drivers/gpu/drm/xe/xe_guc_capture.h | 10 +++ drivers/gpu/drm/xe/xe_hw_engine.c | 73 ++++++++--------- drivers/gpu/drm/xe/xe_hw_engine_types.h | 103 ++++++++++++------------ 4 files changed, 195 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_capture.c b/drivers/gpu/drm/xe/xe_guc_capture.c index 52f1bacc08ff..d126d32875f9 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture.c +++ b/drivers/gpu/drm/xe/xe_guc_capture.c @@ -169,6 +169,33 @@ static const struct __guc_mmio_reg_descr_group xe_lp_lists[] = { {} }; +struct __reg_map_descr capture_engine_reg[] = { + {offsetof(struct snap_shot_regs, ring_hwstam), RING_HWSTAM(0)}, + {offsetof(struct snap_shot_regs, ring_hws_pga), RING_HWS_PGA(0)}, + {offsetof(struct snap_shot_regs, ring_execlist_status_lo), RING_EXECLIST_STATUS_LO(0)}, + {offsetof(struct snap_shot_regs, ring_execlist_status_hi), RING_EXECLIST_STATUS_HI(0)}, + {offsetof(struct snap_shot_regs, ring_execlist_sq_contents_lo), RING_EXECLIST_SQ_CONTENTS_LO(0)}, + {offsetof(struct snap_shot_regs, ring_execlist_sq_contents_hi), RING_EXECLIST_SQ_CONTENTS_HI(0)}, + {offsetof(struct snap_shot_regs, ring_start), RING_START(0)}, + {offsetof(struct snap_shot_regs, ring_head), RING_HEAD(0)}, + {offsetof(struct snap_shot_regs, ring_tail), RING_TAIL(0)}, + {offsetof(struct snap_shot_regs, ring_ctl), RING_CTL(0)}, + {offsetof(struct snap_shot_regs, ring_mi_mode), RING_MI_MODE(0)}, + {offsetof(struct snap_shot_regs, ring_mode), RING_MODE(0)}, + {offsetof(struct snap_shot_regs, ring_imr), RING_IMR(0)}, + {offsetof(struct snap_shot_regs, ring_esr), RING_ESR(0)}, + {offsetof(struct snap_shot_regs, ring_emr), RING_EMR(0)}, + {offsetof(struct snap_shot_regs, ring_eir), RING_EIR(0)}, + {offsetof(struct snap_shot_regs, ring_acthd_udw), RING_ACTHD_UDW(0)}, + {offsetof(struct snap_shot_regs, ring_acthd), RING_ACTHD(0)}, + {offsetof(struct snap_shot_regs, ring_bbaddr_udw), RING_BBADDR_UDW(0)}, + {offsetof(struct snap_shot_regs, ring_bbaddr), RING_BBADDR(0)}, + {offsetof(struct snap_shot_regs, ring_dma_fadd_udw), RING_DMA_FADD_UDW(0)}, + {offsetof(struct snap_shot_regs, ring_dma_fadd), RING_DMA_FADD(0)}, + {offsetof(struct snap_shot_regs, ipehr), RING_IPEHR(0)}, + {offsetof(struct snap_shot_regs, rcu_mode), RCU_MODE}, +}; + static const char * capture_list_type_names [] = { "Global", "Class", @@ -1304,4 +1331,74 @@ int xe_guc_capture_init(struct xe_guc *guc) return 0; } -#endif \ No newline at end of file +inline struct __reg_map_descr *xe_guc_capture_get_register_map(int *count) +{ + *count = ARRAY_SIZE(capture_engine_reg); + return capture_engine_reg; +} + +static void cp_reg_to_snapshot(u32 offset, u32 value, struct snap_shot_regs *regs) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(capture_engine_reg); i++) + if (offset == capture_engine_reg[i].reg.addr) { + u32 *field = (u32 *)((uintptr_t)regs + capture_engine_reg[i].dst_offset); + *field = value; + return; + } +} + +static void guc_capture_find_ecode(struct __guc_capture_parsed_output *node, + struct xe_hw_engine_snapshot *snapshot) +{ + struct gcap_reg_list_info *reginfo; + struct guc_mmio_reg *regs; + int i; + + if (!node) + return; + + reginfo = node->reginfo + GUC_CAPTURE_LIST_TYPE_ENGINE_INSTANCE; + regs = reginfo->regs; + for (i = 0; i < reginfo->num_regs; i++) + cp_reg_to_snapshot(regs[i].offset, regs[i].value, &snapshot->reg); +} + +/** + * xe_hw_engine_snapshot_from_capture - Take a quick snapshot of the HW Engine. + * @hwe: Xe HW Engine. + * @snapshot: Xe HW Engine snapshot object to save data, copied from error capture + * + * This can be printed out in a later stage like during dev_coredump + * analysis. + * + * Returns: None + */ +void +xe_hw_engine_snapshot_from_capture(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot *snapshot) +{ + struct xe_gt *gt = hwe->gt; + struct xe_guc *guc = >->uc.guc; + struct __guc_capture_parsed_output *n, *ntmp; + + if (!guc->capture) + return; + + /* + * Look for a matching GuC reported error capture node from + * the internal output link-list based on engine class and instance. + */ + list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) { + u32 hwe_guc_class = xe_engine_class_to_guc_class(hwe->class); + + if (n->eng_class == hwe_guc_class + && n->eng_inst == hwe->instance) { + guc_capture_find_ecode(n, snapshot); + list_del(&n->link); + return; + } + } +} + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_capture.h b/drivers/gpu/drm/xe/xe_guc_capture.h index efa4f177aab5..9f48e2d752d8 100644 --- a/drivers/gpu/drm/xe/xe_guc_capture.h +++ b/drivers/gpu/drm/xe/xe_guc_capture.h @@ -14,6 +14,11 @@ struct xe_hw_engine; struct xe_gt; struct xe_guc; +struct __reg_map_descr { + u32 dst_offset; + struct xe_reg reg; +}; + bool xe_guc_capture_is_matching_engine(struct xe_gt *gt, struct xe_exec_queue *ce, struct xe_hw_engine *engine); void xe_guc_capture_process(struct xe_guc *guc); @@ -21,5 +26,10 @@ int xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type, u32 classid, int xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type, u32 classid, size_t *size); int xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size); int xe_guc_capture_init(struct xe_guc *guc); +struct __reg_map_descr *xe_guc_capture_get_register_map(int *count); +void xe_hw_engine_snapshot_from_capture(struct xe_hw_engine *hwe, + struct xe_hw_engine_snapshot *snapshot); +void xe_hw_engine_snapshot_from_engine(struct xe_hw_engine *hwe, + struct xe_hw_engine_snapshot *snapshot); #endif /* _XE_GUC_CAPTURE_H */ diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index f56d301078b2..281afb564777 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -17,6 +17,7 @@ #include "xe_gt.h" #include "xe_gt_ccs_mode.h" #include "xe_gt_topology.h" +#include "xe_guc_capture.h" #include "xe_hw_fence.h" #include "xe_irq.h" #include "xe_lrc.h" @@ -739,6 +740,30 @@ void xe_hw_engine_handle_irq(struct xe_hw_engine *hwe, u16 intr_vec) xe_hw_fence_irq_run(hwe->fence_irq); } +/** + * xe_hw_engine_snapshot_from_capture - Take a quick snapshot of the HW Engine. + * @hwe: Xe HW Engine. + * @snapshot: Point to the Xe HW Engine snapshot object to save data. + * + * This can be printed out in a later stage like during dev_coredump + * analysis. + * + * Returns: None + */ +void +xe_hw_engine_snapshot_from_engine(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot *snapshot) +{ + int count, i; + struct __reg_map_descr *map = xe_guc_capture_get_register_map(&count); + + for (i = 0; i < count; i++) { + u32 *field = (u32 *)((uintptr_t)&snapshot->reg + map[i].dst_offset); + *field = hw_engine_mmio_read32(hwe, map[i].reg); + } + if (snapshot->class == XE_ENGINE_CLASS_COMPUTE) + snapshot->reg.rcu_mode = xe_mmio_read32(hwe->gt, RCU_MODE); +} + /** * xe_hw_engine_snapshot_capture - Take a quick snapshot of the HW Engine. * @hwe: Xe HW Engine. @@ -775,46 +800,16 @@ xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe) hwe->domain); snapshot->mmio_base = hwe->mmio_base; - snapshot->reg.ring_hwstam = hw_engine_mmio_read32(hwe, RING_HWSTAM(0)); - snapshot->reg.ring_hws_pga = hw_engine_mmio_read32(hwe, - RING_HWS_PGA(0)); - snapshot->reg.ring_execlist_status_lo = - hw_engine_mmio_read32(hwe, RING_EXECLIST_STATUS_LO(0)); - snapshot->reg.ring_execlist_status_hi = - hw_engine_mmio_read32(hwe, RING_EXECLIST_STATUS_HI(0)); - snapshot->reg.ring_execlist_sq_contents_lo = - hw_engine_mmio_read32(hwe, - RING_EXECLIST_SQ_CONTENTS_LO(0)); - snapshot->reg.ring_execlist_sq_contents_hi = - hw_engine_mmio_read32(hwe, - RING_EXECLIST_SQ_CONTENTS_HI(0)); - snapshot->reg.ring_start = hw_engine_mmio_read32(hwe, RING_START(0)); - snapshot->reg.ring_head = - hw_engine_mmio_read32(hwe, RING_HEAD(0)) & HEAD_ADDR; - snapshot->reg.ring_tail = - hw_engine_mmio_read32(hwe, RING_TAIL(0)) & TAIL_ADDR; - snapshot->reg.ring_ctl = hw_engine_mmio_read32(hwe, RING_CTL(0)); - snapshot->reg.ring_mi_mode = - hw_engine_mmio_read32(hwe, RING_MI_MODE(0)); - snapshot->reg.ring_mode = hw_engine_mmio_read32(hwe, RING_MODE(0)); - snapshot->reg.ring_imr = hw_engine_mmio_read32(hwe, RING_IMR(0)); - snapshot->reg.ring_esr = hw_engine_mmio_read32(hwe, RING_ESR(0)); - snapshot->reg.ring_emr = hw_engine_mmio_read32(hwe, RING_EMR(0)); - snapshot->reg.ring_eir = hw_engine_mmio_read32(hwe, RING_EIR(0)); - snapshot->reg.ring_acthd_udw = - hw_engine_mmio_read32(hwe, RING_ACTHD_UDW(0)); - snapshot->reg.ring_acthd = hw_engine_mmio_read32(hwe, RING_ACTHD(0)); - snapshot->reg.ring_bbaddr_udw = - hw_engine_mmio_read32(hwe, RING_BBADDR_UDW(0)); - snapshot->reg.ring_bbaddr = hw_engine_mmio_read32(hwe, RING_BBADDR(0)); - snapshot->reg.ring_dma_fadd_udw = - hw_engine_mmio_read32(hwe, RING_DMA_FADD_UDW(0)); - snapshot->reg.ring_dma_fadd = - hw_engine_mmio_read32(hwe, RING_DMA_FADD(0)); - snapshot->reg.ipehr = hw_engine_mmio_read32(hwe, RING_IPEHR(0)); +#if IS_ENABLED(CONFIG_DRM_XE_CAPTURE_ERROR) + if (xe_device_uc_enabled(gt_to_xe(hwe->gt))) + xe_hw_engine_snapshot_from_capture(hwe, snapshot); + else +#endif + xe_hw_engine_snapshot_from_engine(hwe, snapshot); - if (snapshot->class == XE_ENGINE_CLASS_COMPUTE) - snapshot->reg.rcu_mode = xe_mmio_read32(hwe->gt, RCU_MODE); + /* appy mask for ring head and tail */ + snapshot->reg.ring_head &= HEAD_ADDR; + snapshot->reg.ring_tail &= TAIL_ADDR; return snapshot; } diff --git a/drivers/gpu/drm/xe/xe_hw_engine_types.h b/drivers/gpu/drm/xe/xe_hw_engine_types.h index c258228b244f..0d0881f1d53b 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_types.h +++ b/drivers/gpu/drm/xe/xe_hw_engine_types.h @@ -153,6 +153,58 @@ struct xe_hw_engine { struct xe_hw_engine_class_intf *eclass; }; +/** @reg: Useful MMIO register snapshot */ +struct snap_shot_regs { + /** @ring_hwstam: RING_HWSTAM */ + u32 ring_hwstam; + /** @ring_hws_pga: RING_HWS_PGA */ + u32 ring_hws_pga; + /** @ring_execlist_status_lo: RING_EXECLIST_STATUS_LO */ + u32 ring_execlist_status_lo; + /** @ring_execlist_status_hi: RING_EXECLIST_STATUS_HI */ + u32 ring_execlist_status_hi; + /** @ring_execlist_sq_contents_lo: RING_EXECLIST_SQ_CONTENTS */ + u32 ring_execlist_sq_contents_lo; + /** @ring_execlist_sq_contents_hi: RING_EXECLIST_SQ_CONTENTS + 4 */ + u32 ring_execlist_sq_contents_hi; + /** @ring_start: RING_START */ + u32 ring_start; + /** @ring_head: RING_HEAD */ + u32 ring_head; + /** @ring_tail: RING_TAIL */ + u32 ring_tail; + /** @ring_ctl: RING_CTL */ + u32 ring_ctl; + /** @ring_mi_mode: RING_MI_MODE */ + u32 ring_mi_mode; + /** @ring_mode: RING_MODE */ + u32 ring_mode; + /** @ring_imr: RING_IMR */ + u32 ring_imr; + /** @ring_esr: RING_ESR */ + u32 ring_esr; + /** @ring_emr: RING_EMR */ + u32 ring_emr; + /** @ring_eir: RING_EIR */ + u32 ring_eir; + /** @ring_acthd_udw: RING_ACTHD_UDW */ + u32 ring_acthd_udw; + /** @ring_acthd: RING_ACTHD */ + u32 ring_acthd; + /** @ring_bbaddr_udw: RING_BBADDR_UDW */ + u32 ring_bbaddr_udw; + /** @ring_bbaddr: RING_BBADDR */ + u32 ring_bbaddr; + /** @ring_dma_fadd_udw: RING_DMA_FADD_UDW */ + u32 ring_dma_fadd_udw; + /** @ring_dma_fadd: RING_DMA_FADD */ + u32 ring_dma_fadd; + /** @ipehr: IPEHR */ + u32 ipehr; + /** @rcu_mode: RCU_MODE */ + u32 rcu_mode; +}; + /** * struct xe_hw_engine_snapshot - Hardware engine snapshot * @@ -175,56 +227,7 @@ struct xe_hw_engine_snapshot { /** @mmio_base: MMIO base address of this hw engine*/ u32 mmio_base; /** @reg: Useful MMIO register snapshot */ - struct { - /** @ring_hwstam: RING_HWSTAM */ - u32 ring_hwstam; - /** @ring_hws_pga: RING_HWS_PGA */ - u32 ring_hws_pga; - /** @ring_execlist_status_lo: RING_EXECLIST_STATUS_LO */ - u32 ring_execlist_status_lo; - /** @ring_execlist_status_hi: RING_EXECLIST_STATUS_HI */ - u32 ring_execlist_status_hi; - /** @ring_execlist_sq_contents_lo: RING_EXECLIST_SQ_CONTENTS */ - u32 ring_execlist_sq_contents_lo; - /** @ring_execlist_sq_contents_hi: RING_EXECLIST_SQ_CONTENTS + 4 */ - u32 ring_execlist_sq_contents_hi; - /** @ring_start: RING_START */ - u32 ring_start; - /** @ring_head: RING_HEAD */ - u32 ring_head; - /** @ring_tail: RING_TAIL */ - u32 ring_tail; - /** @ring_ctl: RING_CTL */ - u32 ring_ctl; - /** @ring_mi_mode: RING_MI_MODE */ - u32 ring_mi_mode; - /** @ring_mode: RING_MODE */ - u32 ring_mode; - /** @ring_imr: RING_IMR */ - u32 ring_imr; - /** @ring_esr: RING_ESR */ - u32 ring_esr; - /** @ring_emr: RING_EMR */ - u32 ring_emr; - /** @ring_eir: RING_EIR */ - u32 ring_eir; - /** @ring_acthd_udw: RING_ACTHD_UDW */ - u32 ring_acthd_udw; - /** @ring_acthd: RING_ACTHD */ - u32 ring_acthd; - /** @ring_bbaddr_udw: RING_BBADDR_UDW */ - u32 ring_bbaddr_udw; - /** @ring_bbaddr: RING_BBADDR */ - u32 ring_bbaddr; - /** @ring_dma_fadd_udw: RING_DMA_FADD_UDW */ - u32 ring_dma_fadd_udw; - /** @ring_dma_fadd: RING_DMA_FADD */ - u32 ring_dma_fadd; - /** @ipehr: IPEHR */ - u32 ipehr; - /** @rcu_mode: RCU_MODE */ - u32 rcu_mode; - } reg; + struct snap_shot_regs reg; }; #endif -- 2.34.1