drm/xe: Add a reason string to the devcoredump

There are debug level prints giving more information about the cause
of the hang immediately before core dumps are created. However, not
everyone has debug level prints enabled or saves the dmesg log at all.
So include that information in the dump file itself. Also, at least
one of those prints included the pid as well as the process name. So
include that in the capture too.

v2: Fix kvfree vs kfree and missing kernel-doc (review feedback from
Matthew Brost)
v3: Use GFP_ATOMIC instead of GFP_KERNEL.

Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241128210824.3302147-2-John.C.Harrison@Intel.com
This commit is contained in:
John Harrison 2024-11-28 13:08:22 -08:00
parent 0a7477507b
commit 429915acae
4 changed files with 35 additions and 9 deletions

View File

@ -100,6 +100,7 @@ static ssize_t __xe_devcoredump_read(char *buffer, size_t count,
p = drm_coredump_printer(&iter);
drm_puts(&p, "**** Xe Device Coredump ****\n");
drm_printf(&p, "Reason: %s\n", ss->reason);
drm_puts(&p, "kernel: " UTS_RELEASE "\n");
drm_puts(&p, "module: " KBUILD_MODNAME "\n");
@ -107,7 +108,7 @@ static ssize_t __xe_devcoredump_read(char *buffer, size_t count,
drm_printf(&p, "Snapshot time: %lld.%09ld\n", ts.tv_sec, ts.tv_nsec);
ts = ktime_to_timespec64(ss->boot_time);
drm_printf(&p, "Uptime: %lld.%09ld\n", ts.tv_sec, ts.tv_nsec);
drm_printf(&p, "Process: %s\n", ss->process_name);
drm_printf(&p, "Process: %s [%d]\n", ss->process_name, ss->pid);
xe_device_snapshot_print(xe, &p);
drm_printf(&p, "\n**** GT #%d ****\n", ss->gt->info.id);
@ -139,6 +140,9 @@ static void xe_devcoredump_snapshot_free(struct xe_devcoredump_snapshot *ss)
{
int i;
kfree(ss->reason);
ss->reason = NULL;
xe_guc_log_snapshot_free(ss->guc.log);
ss->guc.log = NULL;
@ -259,8 +263,11 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
ss->snapshot_time = ktime_get_real();
ss->boot_time = ktime_get_boottime();
if (q->vm && q->vm->xef)
if (q->vm && q->vm->xef) {
process_name = q->vm->xef->process_name;
ss->pid = q->vm->xef->pid;
}
strscpy(ss->process_name, process_name);
ss->gt = q->gt;
@ -298,15 +305,18 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump,
* xe_devcoredump - Take the required snapshots and initialize coredump device.
* @q: The faulty xe_exec_queue, where the issue was detected.
* @job: The faulty xe_sched_job, where the issue was detected.
* @fmt: Printf format + args to describe the reason for the core dump
*
* This function should be called at the crash time within the serialized
* gt_reset. It is skipped if we still have the core dump device available
* with the information of the 'first' snapshot.
*/
void xe_devcoredump(struct xe_exec_queue *q, struct xe_sched_job *job)
__printf(3, 4)
void xe_devcoredump(struct xe_exec_queue *q, struct xe_sched_job *job, const char *fmt, ...)
{
struct xe_device *xe = gt_to_xe(q->gt);
struct xe_devcoredump *coredump = &xe->devcoredump;
va_list varg;
if (coredump->captured) {
drm_dbg(&xe->drm, "Multiple hangs are occurring, but only the first snapshot was taken\n");
@ -314,6 +324,11 @@ void xe_devcoredump(struct xe_exec_queue *q, struct xe_sched_job *job)
}
coredump->captured = true;
va_start(varg, fmt);
coredump->snapshot.reason = kvasprintf(GFP_ATOMIC, fmt, varg);
va_end(varg);
devcoredump_snapshot(coredump, q, job);
drm_info(&xe->drm, "Xe device coredump has been created\n");

View File

@ -14,11 +14,12 @@ struct xe_exec_queue;
struct xe_sched_job;
#ifdef CONFIG_DEV_COREDUMP
void xe_devcoredump(struct xe_exec_queue *q, struct xe_sched_job *job);
void xe_devcoredump(struct xe_exec_queue *q, struct xe_sched_job *job, const char *fmt, ...);
int xe_devcoredump_init(struct xe_device *xe);
#else
static inline void xe_devcoredump(struct xe_exec_queue *q,
struct xe_sched_job *job)
struct xe_sched_job *job,
const char *fmt, ...)
{
}

View File

@ -28,6 +28,10 @@ struct xe_devcoredump_snapshot {
ktime_t boot_time;
/** @process_name: Name of process that triggered this gpu hang */
char process_name[TASK_COMM_LEN];
/** @pid: Process id of process that triggered this gpu hang */
pid_t pid;
/** @reason: The reason the coredump was triggered */
char *reason;
/** @gt: Affected GT, used by forcewake for delayed capture */
struct xe_gt *gt;

View File

@ -901,7 +901,8 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w)
if (!ret) {
xe_gt_warn(q->gt, "Schedule disable failed to respond, guc_id=%d\n",
q->guc->id);
xe_devcoredump(q, NULL);
xe_devcoredump(q, NULL, "Schedule disable failed to respond, guc_id=%d\n",
q->guc->id);
xe_sched_submission_start(sched);
xe_gt_reset_async(q->gt);
return;
@ -909,7 +910,7 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w)
}
if (!exec_queue_killed(q) && !xe_lrc_ring_is_idle(q->lrc[0]))
xe_devcoredump(q, NULL);
xe_devcoredump(q, NULL, "LR job cleanup, guc_id=%d", q->guc->id);
xe_sched_submission_start(sched);
}
@ -1136,7 +1137,9 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
xe_gt_warn(guc_to_gt(guc),
"Schedule disable failed to respond, guc_id=%d",
q->guc->id);
xe_devcoredump(q, job);
xe_devcoredump(q, job,
"Schedule disable failed to respond, guc_id=%d, ret=%d, guc_read=%d",
q->guc->id, ret, xe_guc_read_stopped(guc));
set_exec_queue_extra_ref(q);
xe_exec_queue_get(q); /* GT reset owns this */
set_exec_queue_banned(q);
@ -1166,7 +1169,10 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
trace_xe_sched_job_timedout(job);
if (!exec_queue_killed(q))
xe_devcoredump(q, job);
xe_devcoredump(q, job,
"Timedout job - seqno=%u, lrc_seqno=%u, guc_id=%d, flags=0x%lx",
xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job),
q->guc->id, q->flags);
/*
* Kernel jobs should never fail, nor should VM jobs if they do