Merge tag 'drm-intel-gt-next-2025-09-12' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-next

Driver Changes:

- Include the GuC registers in the error state (Daniele)
- Use memdup_user() (Thorsten)
- Selftest improvements (Jonathan)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://lore.kernel.org/r/aMPCfRObHMg6DZAs@jlahtine-mobl
This commit is contained in:
Dave Airlie 2025-09-15 13:16:53 +10:00
commit 2cda9a063d
6 changed files with 116 additions and 12 deletions

View File

@ -2158,18 +2158,12 @@ static int set_context_image(struct i915_gem_context *ctx,
goto out_ce;
}
state = kmalloc(ce->engine->context_size, GFP_KERNEL);
if (!state) {
ret = -ENOMEM;
state = memdup_user(u64_to_user_ptr(user.image), ce->engine->context_size);
if (IS_ERR(state)) {
ret = PTR_ERR(state);
goto out_ce;
}
if (copy_from_user(state, u64_to_user_ptr(user.image),
ce->engine->context_size)) {
ret = -EFAULT;
goto out_state;
}
shmem_state = shmem_create_from_data(ce->engine->name,
state, ce->engine->context_size);
if (IS_ERR(shmem_state)) {

View File

@ -904,9 +904,7 @@ static void active_engine(struct kthread_work *work)
arg->result = PTR_ERR(ce[count]);
pr_err("[%s] Create context #%ld failed: %d!\n",
engine->name, count, arg->result);
if (!count)
return;
while (--count)
while (count--)
intel_context_put(ce[count]);
return;
}

View File

@ -46,6 +46,14 @@ static void guc_prepare_xfer(struct intel_gt *gt)
/* allows for 5us (in 10ns units) before GT can go to RC6 */
intel_uncore_write(uncore, GUC_ARAT_C6DIS, 0x1FF);
}
/*
* Starting from IP 12.50 we need to enable the mirroring of GuC
* internal state to debug registers. This is always enabled on previous
* IPs.
*/
if (GRAPHICS_VER_FULL(uncore->i915) >= IP_VER(12, 50))
intel_uncore_rmw(uncore, GUC_SHIM_CONTROL2, 0, GUC_ENABLE_DEBUG_REG);
}
static int guc_xfer_rsa_mmio(struct intel_uc_fw *guc_fw,

View File

@ -96,6 +96,7 @@
#define GUC_GEN10_SHIM_WC_ENABLE (1<<21)
#define GUC_SHIM_CONTROL2 _MMIO(0xc068)
#define GUC_ENABLE_DEBUG_REG (1<<11)
#define GUC_IS_PRIVILEGED (1<<29)
#define GSC_LOADS_HUC (1<<30)

View File

@ -685,6 +685,74 @@ static void err_print_guc_ctb(struct drm_i915_error_state_buf *m,
ctb->head, ctb->tail, ctb->desc_offset, ctb->cmds_offset, ctb->size);
}
/* This list includes registers that are useful in debugging GuC hangs. */
const struct {
u32 start;
u32 count;
} guc_hw_reg_state[] = {
{ 0xc0b0, 2 },
{ 0xc000, 65 },
{ 0xc140, 1 },
{ 0xc180, 16 },
{ 0xc1dc, 10 },
{ 0xc300, 79 },
{ 0xc4b4, 47 },
{ 0xc574, 1 },
{ 0xc57c, 1 },
{ 0xc584, 11 },
{ 0xc5c0, 8 },
{ 0xc5e4, 1 },
{ 0xc5ec, 103 },
{ 0xc7c0, 1 },
{ 0xc0b0, 2 }
};
static u32 print_range_line(struct drm_i915_error_state_buf *m, u32 start, u32 *dump, u32 count)
{
if (count >= 8) {
err_printf(m, "[0x%04x] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
start, dump[0], dump[1], dump[2], dump[3],
dump[4], dump[5], dump[6], dump[7]);
return 8;
} else if (count >= 4) {
err_printf(m, "[0x%04x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
start, dump[0], dump[1], dump[2], dump[3]);
return 4;
} else if (count >= 2) {
err_printf(m, "[0x%04x] 0x%08x 0x%08x\n", start, dump[0], dump[1]);
return 2;
}
err_printf(m, "[0x%04x] 0x%08x\n", start, dump[0]);
return 1;
}
static void err_print_guc_hw_state(struct drm_i915_error_state_buf *m, u32 *hw_state)
{
u32 total = 0;
int i;
if (!hw_state)
return;
err_printf(m, "GuC Register State:\n");
for (i = 0; i < ARRAY_SIZE(guc_hw_reg_state); i++) {
u32 entry = 0;
while (entry < guc_hw_reg_state[i].count) {
u32 start = guc_hw_reg_state[i].start + entry * sizeof(u32);
u32 count = guc_hw_reg_state[i].count - entry;
u32 *values = hw_state + total + entry;
entry += print_range_line(m, start, values, count);
}
GEM_BUG_ON(entry != guc_hw_reg_state[i].count);
total += entry;
}
}
static void err_print_uc(struct drm_i915_error_state_buf *m,
const struct intel_uc_coredump *error_uc)
{
@ -693,6 +761,7 @@ static void err_print_uc(struct drm_i915_error_state_buf *m,
intel_uc_fw_dump(&error_uc->guc_fw, &p);
intel_uc_fw_dump(&error_uc->huc_fw, &p);
err_printf(m, "GuC timestamp: 0x%08x\n", error_uc->guc.timestamp);
err_print_guc_hw_state(m, error_uc->guc.hw_state);
intel_gpu_error_print_vma(m, NULL, error_uc->guc.vma_log);
err_printf(m, "GuC CTB fence: %d\n", error_uc->guc.last_fence);
err_print_guc_ctb(m, "Send", error_uc->guc.ctb + 0);
@ -1025,6 +1094,7 @@ static void cleanup_uc(struct intel_uc_coredump *uc)
kfree(uc->huc_fw.file_wanted.path);
i915_vma_coredump_free(uc->guc.vma_log);
i915_vma_coredump_free(uc->guc.vma_ctb);
kfree(uc->guc.hw_state);
kfree(uc);
}
@ -1721,6 +1791,37 @@ static void gt_record_guc_ctb(struct intel_ctb_coredump *saved,
saved->cmds_offset = ((void *)ctb->cmds) - blob_ptr;
}
static u32 read_guc_state_reg(struct intel_uncore *uncore, int range, int count)
{
GEM_BUG_ON(range >= ARRAY_SIZE(guc_hw_reg_state));
GEM_BUG_ON(count >= guc_hw_reg_state[range].count);
return intel_uncore_read(uncore,
_MMIO(guc_hw_reg_state[range].start + count * sizeof(u32)));
}
static void gt_record_guc_hw_state(struct intel_uncore *uncore,
struct intel_uc_coredump *error_uc)
{
u32 *hw_state;
u32 count = 0;
int i, j;
for (i = 0; i < ARRAY_SIZE(guc_hw_reg_state); i++)
count += guc_hw_reg_state[i].count;
hw_state = kcalloc(count, sizeof(u32), ALLOW_FAIL);
if (!hw_state)
return;
count = 0;
for (i = 0; i < ARRAY_SIZE(guc_hw_reg_state); i++)
for (j = 0; j < guc_hw_reg_state[i].count; j++)
hw_state[count++] = read_guc_state_reg(uncore, i, j);
error_uc->guc.hw_state = hw_state;
}
static struct intel_uc_coredump *
gt_record_uc(struct intel_gt_coredump *gt,
struct i915_vma_compress *compress)
@ -1755,6 +1856,7 @@ gt_record_uc(struct intel_gt_coredump *gt,
uc->guc.ct.ctbs.send.desc, (struct intel_guc *)&uc->guc);
gt_record_guc_ctb(error_uc->guc.ctb + 1, &uc->guc.ct.ctbs.recv,
uc->guc.ct.ctbs.send.desc, (struct intel_guc *)&uc->guc);
gt_record_guc_hw_state(gt->_gt->uncore, error_uc);
return error_uc;
}

View File

@ -177,6 +177,7 @@ struct intel_gt_coredump {
struct intel_ctb_coredump ctb[2];
struct i915_vma_coredump *vma_ctb;
struct i915_vma_coredump *vma_log;
u32 *hw_state;
u32 timestamp;
u16 last_fence;
bool is_guc_capture;