Skip to content

Commit e3e6bea

Browse files
johnharr-intelgregkh
authored andcommitted
drm/xe/devcoredump: Add ASCII85 dump helper function
[ Upstream commit ec1455c ] There is a need to include the GuC log and other large binary objects in core dumps and via dmesg. So add a helper for dumping to a printer function via conversion to ASCII85 encoding. Another issue with dumping such a large buffer is that it can be slow, especially if dumping to dmesg over a serial port. So add a yield to prevent the 'task has been stuck for 120s' kernel hang check feature from firing. v2: Add a prefix to the output string. Fix memory allocation bug. v3: Correct a string size calculation and clean up a define (review feedback from Julia F). Signed-off-by: John Harrison <John.C.Harrison@Intel.com> Reviewed-by: Julia Filipchuk <julia.filipchuk@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20241003004611.2323493-5-John.C.Harrison@Intel.com Stable-dep-of: 5dce85f ("drm/xe: Move the coredump registration to the worker thread") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 47c45a0 commit e3e6bea

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

drivers/gpu/drm/xe/xe_devcoredump.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "xe_devcoredump.h"
77
#include "xe_devcoredump_types.h"
88

9+
#include <linux/ascii85.h>
910
#include <linux/devcoredump.h>
1011
#include <generated/utsrelease.h>
1112

@@ -315,3 +316,89 @@ int xe_devcoredump_init(struct xe_device *xe)
315316
}
316317

317318
#endif
319+
320+
/**
321+
* xe_print_blob_ascii85 - print a BLOB to some useful location in ASCII85
322+
*
323+
* The output is split to multiple lines because some print targets, e.g. dmesg
324+
* cannot handle arbitrarily long lines. Note also that printing to dmesg in
325+
* piece-meal fashion is not possible, each separate call to drm_puts() has a
326+
* line-feed automatically added! Therefore, the entire output line must be
327+
* constructed in a local buffer first, then printed in one atomic output call.
328+
*
329+
* There is also a scheduler yield call to prevent the 'task has been stuck for
330+
* 120s' kernel hang check feature from firing when printing to a slow target
331+
* such as dmesg over a serial port.
332+
*
333+
* TODO: Add compression prior to the ASCII85 encoding to shrink huge buffers down.
334+
*
335+
* @p: the printer object to output to
336+
* @prefix: optional prefix to add to output string
337+
* @blob: the Binary Large OBject to dump out
338+
* @offset: offset in bytes to skip from the front of the BLOB, must be a multiple of sizeof(u32)
339+
* @size: the size in bytes of the BLOB, must be a multiple of sizeof(u32)
340+
*/
341+
void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix,
342+
const void *blob, size_t offset, size_t size)
343+
{
344+
const u32 *blob32 = (const u32 *)blob;
345+
char buff[ASCII85_BUFSZ], *line_buff;
346+
size_t line_pos = 0;
347+
348+
#define DMESG_MAX_LINE_LEN 800
349+
#define MIN_SPACE (ASCII85_BUFSZ + 2) /* 85 + "\n\0" */
350+
351+
if (size & 3)
352+
drm_printf(p, "Size not word aligned: %zu", size);
353+
if (offset & 3)
354+
drm_printf(p, "Offset not word aligned: %zu", size);
355+
356+
line_buff = kzalloc(DMESG_MAX_LINE_LEN, GFP_KERNEL);
357+
if (IS_ERR_OR_NULL(line_buff)) {
358+
drm_printf(p, "Failed to allocate line buffer: %pe", line_buff);
359+
return;
360+
}
361+
362+
blob32 += offset / sizeof(*blob32);
363+
size /= sizeof(*blob32);
364+
365+
if (prefix) {
366+
strscpy(line_buff, prefix, DMESG_MAX_LINE_LEN - MIN_SPACE - 2);
367+
line_pos = strlen(line_buff);
368+
369+
line_buff[line_pos++] = ':';
370+
line_buff[line_pos++] = ' ';
371+
}
372+
373+
while (size--) {
374+
u32 val = *(blob32++);
375+
376+
strscpy(line_buff + line_pos, ascii85_encode(val, buff),
377+
DMESG_MAX_LINE_LEN - line_pos);
378+
line_pos += strlen(line_buff + line_pos);
379+
380+
if ((line_pos + MIN_SPACE) >= DMESG_MAX_LINE_LEN) {
381+
line_buff[line_pos++] = '\n';
382+
line_buff[line_pos++] = 0;
383+
384+
drm_puts(p, line_buff);
385+
386+
line_pos = 0;
387+
388+
/* Prevent 'stuck thread' time out errors */
389+
cond_resched();
390+
}
391+
}
392+
393+
if (line_pos) {
394+
line_buff[line_pos++] = '\n';
395+
line_buff[line_pos++] = 0;
396+
397+
drm_puts(p, line_buff);
398+
}
399+
400+
kfree(line_buff);
401+
402+
#undef MIN_SPACE
403+
#undef DMESG_MAX_LINE_LEN
404+
}

drivers/gpu/drm/xe/xe_devcoredump.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#ifndef _XE_DEVCOREDUMP_H_
77
#define _XE_DEVCOREDUMP_H_
88

9+
#include <linux/types.h>
10+
11+
struct drm_printer;
912
struct xe_device;
1013
struct xe_sched_job;
1114

@@ -23,4 +26,7 @@ static inline int xe_devcoredump_init(struct xe_device *xe)
2326
}
2427
#endif
2528

29+
void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix,
30+
const void *blob, size_t offset, size_t size);
31+
2632
#endif

0 commit comments

Comments
 (0)