}
}
+/*
+ * 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;