diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index 38f648b98868..57ef4f527ed0 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -2155,6 +2155,102 @@ void xe_lrc_dump_default(struct drm_printer *p, } } +/* + * Lookup the value of a register within the offset/value pairs of an + * MI_LOAD_REGISTER_IMM instruction. + * + * Return -ENOENT if the register is not present in the MI_LRI instruction. + */ +static int lookup_reg_in_mi_lri(u32 offset, u32 *value, + const u32 *dword_pair, int num_regs) +{ + for (int i = 0; i < num_regs; i++) { + if (dword_pair[2 * i] == offset) { + *value = dword_pair[2 * i + 1]; + return 0; + } + } + + return -ENOENT; +} + +/* + * Lookup the value of a register in a specific engine type's default LRC. + * + * Return -EINVAL if the default LRC doesn't exist, or ENOENT if the register + * cannot be found in the default LRC. + */ +int xe_lrc_lookup_default_reg_value(struct xe_gt *gt, + enum xe_engine_class hwe_class, + u32 offset, + u32 *value) +{ + u32 *dw; + int remaining_dw, ret; + + if (!gt->default_lrc[hwe_class]) + return -EINVAL; + + /* + * Skip the beginning of the LRC since it contains the per-process + * hardware status page. + */ + dw = gt->default_lrc[hwe_class] + LRC_PPHWSP_SIZE; + remaining_dw = (xe_gt_lrc_size(gt, hwe_class) - LRC_PPHWSP_SIZE) / 4; + + while (remaining_dw > 0) { + u32 num_dw = instr_dw(*dw); + + if (num_dw > remaining_dw) + num_dw = remaining_dw; + + switch (*dw & XE_INSTR_CMD_TYPE) { + case XE_INSTR_MI: + switch (*dw & MI_OPCODE) { + case MI_BATCH_BUFFER_END: + /* End of LRC; register not found */ + return -ENOENT; + + case MI_NOOP: + case MI_TOPOLOGY_FILTER: + /* + * MI_NOOP and MI_TOPOLOGY_FILTER don't have + * a length field and are always 1-dword + * instructions. + */ + remaining_dw--; + dw++; + break; + + case MI_LOAD_REGISTER_IMM: + ret = lookup_reg_in_mi_lri(offset, value, + dw + 1, (num_dw - 1) / 2); + if (ret == 0) + return 0; + + fallthrough; + + default: + /* + * Jump to next instruction based on length + * field. + */ + remaining_dw -= num_dw; + dw += num_dw; + break; + } + break; + + default: + /* Jump to next instruction based on length field. */ + remaining_dw -= num_dw; + dw += num_dw; + } + } + + return -ENOENT; +} + struct instr_state { u32 instr; u16 num_dw; diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h index c307a3fd9ea2..3e500004f1ae 100644 --- a/drivers/gpu/drm/xe/xe_lrc.h +++ b/drivers/gpu/drm/xe/xe_lrc.h @@ -133,6 +133,10 @@ size_t xe_lrc_skip_size(struct xe_device *xe); void xe_lrc_dump_default(struct drm_printer *p, struct xe_gt *gt, enum xe_engine_class); +int xe_lrc_lookup_default_reg_value(struct xe_gt *gt, + enum xe_engine_class hwe_class, + u32 offset, + u32 *value); u32 *xe_lrc_emit_hwe_state_instructions(struct xe_exec_queue *q, u32 *cs);