|
6 | 6 | #include "xe_devcoredump.h"
|
7 | 7 | #include "xe_devcoredump_types.h"
|
8 | 8 |
|
| 9 | +#include <linux/ascii85.h> |
9 | 10 | #include <linux/devcoredump.h>
|
10 | 11 | #include <generated/utsrelease.h>
|
11 | 12 |
|
@@ -315,3 +316,89 @@ int xe_devcoredump_init(struct xe_device *xe)
|
315 | 316 | }
|
316 | 317 |
|
317 | 318 | #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 | +} |
0 commit comments