From: Jocelyn Falempe <jfalempe@redhat.com>
To: Mark Brown <broonie@kernel.org>, Dave Airlie <airlied@redhat.com>,
DRI <dri-devel@lists.freedesktop.org>
Cc: Devin Wittmayer <lucid_duck@justthetip.ca>,
Intel Graphics <intel-gfx@lists.freedesktop.org>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
Linux Next Mailing List <linux-next@vger.kernel.org>,
luyuantao <luyuantao@kylinos.cn>,
Simona Vetter <simona.vetter@ffwll.ch>,
Thomas Zimmermann <tzimmermann@suse.de>
Subject: Re: linux-next: manual merge of the drm tree with the drm-misc-fixes tree
Date: Tue, 20 Oct 2026 09:30:12 +0200 [thread overview]
Message-ID: <4cb04699-c607-4f20-be66-0d8e21666af5@redhat.com> (raw)
In-Reply-To: <atZBBqj4ON6kYWSK@sirena.co.uk>
On 10/19/26 18:10, Mark Brown wrote:
> Hi all,
>
> Today's linux-next merge of the drm tree got a conflict in:
>
> drivers/gpu/drm/drm_panic.c
>
> between commits:
>
> 1ba6405638439 ("drm/panic: Fix kmsg screen hang on a long log line")
> b537d87d2632c ("drm/panic: Fix the loop that causes kmsg to not display correctly")
> 3706caf4da279 ("drm/panic: Accept a trailing newline in panic_screen")
>
> from the drm-misc-fixes tree and commit:
>
> 5c3d323984fd1 ("drm/panic: Move panic display code into helper library")
>
> from the drm tree. This obviously isn't the right merge, it drops the
> fixes.
>
> I fixed it up (see below) and can carry the fix as necessary. This
> is now fixed as far as linux-next is concerned, but any non trivial
> conflicts should be mentioned to your upstream maintainer when your tree
> is submitted for merging. You may also want to consider cooperating
> with the maintainer of the conflicting tree to minimise any particularly
> complex conflicts.
Sorry, normally I fixed this conflict in drm-tip, but maybe I missed
something.
Devin has the right conflict resolution, some of the code has moved to
drm_panic_helper.c, and two of the 3 commits should be applied there.
Best regards,
--
Jocelyn
>
> diff --combined drivers/gpu/drm/drm_panic.c
> index 5109bfd5d8891,9fe97c4eda6c8..0000000000000
> --- a/drivers/gpu/drm/drm_panic.c
> +++ b/drivers/gpu/drm/drm_panic.c
> @@@ -7,33 -7,23 +7,23 @@@
> */
>
> #include <linux/export.h>
> - #include <linux/font.h>
> - #include <linux/highmem.h>
> #include <linux/init.h>
> - #include <linux/iosys-map.h>
> #include <linux/kdebug.h>
> #include <linux/kmsg_dump.h>
> - #include <linux/linux_logo.h>
> #include <linux/list.h>
> #include <linux/math.h>
> #include <linux/module.h>
> #include <linux/overflow.h>
> #include <linux/printk.h>
> #include <linux/types.h>
> - #include <linux/utsname.h>
> - #include <linux/zlib.h>
>
> #include <drm/drm_drv.h>
> - #include <drm/drm_fourcc.h>
> - #include <drm/drm_framebuffer.h>
> - #include <drm/drm_modeset_helper_vtables.h>
> #include <drm/drm_panic.h>
> #include <drm/drm_plane.h>
> #include <drm/drm_print.h>
> - #include <drm/drm_rect.h>
>
> #include "drm_crtc_internal.h"
> - #include "drm_draw_internal.h"
> + #include "drm_panic_internal.h"
>
> MODULE_AUTHOR("Jocelyn Falempe");
> MODULE_DESCRIPTION("DRM panic handler");
> @@@ -42,789 -32,25 +32,25 @@@ MODULE_LICENSE("GPL")
> /**
> * DOC: overview
> *
> - * To enable DRM panic for a driver, the primary plane must implement a
> - * &drm_plane_helper_funcs.get_scanout_buffer helper function. It is then
> - * automatically registered to the drm panic handler.
> - * When a panic occurs, the &drm_plane_helper_funcs.get_scanout_buffer will be
> - * called, and the driver can provide a framebuffer so the panic handler can
> - * draw the panic screen on it. Currently only linear buffer and a few color
> - * formats are supported.
> - * Optionally the driver can also provide a &drm_plane_helper_funcs.panic_flush
> - * callback, that will be called after that, to send additional commands to the
> - * hardware to make the scanout buffer visible.
> - */
> -
> - /*
> - * This module displays a user friendly message on screen when a kernel panic
> - * occurs. This is conflicting with fbcon, so you can only enable it when fbcon
> - * is disabled.
> - * It's intended for end-user, so have minimal technical/debug information.
> + * This module displays a user friendly message on screen when a kernel
> + * panic occurs. It's intended for end users and therefore have minimal
> + * technical/debug information.
> *
> - * Implementation details:
> + * To enable DRM panic for a driver, the at least one primary plane must
> + * implement struct &drm_plane_funcs.display_panic_screen. The plane is
> + * then automatically registered to the drm panic handler.
> *
> - * It is a panic handler, so it can't take lock, allocate memory, run tasks/irq,
> - * or attempt to sleep. It's a best effort, and it may not be able to display
> - * the message in all situations (like if the panic occurs in the middle of a
> - * modesetting).
> - * It will display only one static frame, so performance optimizations are low
> - * priority as the machine is already in an unusable state.
> + * When a panic occurs, the DRM panic handler calls struct
> + * &drm_plane_funcs.display_panic_screen. See
> + * drm_plane_helper_display_panic_screen() for a generic implementation.
> */
>
> - struct drm_panic_line {
> - u32 len;
> - const char *txt;
> - };
> -
> - #define PANIC_LINE(s) {.len = sizeof(s) - 1, .txt = s}
> -
> - static struct drm_panic_line panic_msg[] = {
> - PANIC_LINE("KERNEL PANIC!"),
> - PANIC_LINE(""),
> - PANIC_LINE("Please reboot your computer."),
> - PANIC_LINE(""),
> - PANIC_LINE(""), /* will be replaced by the panic description */
> - };
> -
> - static const size_t panic_msg_lines = ARRAY_SIZE(panic_msg);
> -
> - static const struct drm_panic_line logo_ascii[] = {
> - PANIC_LINE(" .--. _"),
> - PANIC_LINE(" |o_o | | |"),
> - PANIC_LINE(" |:_/ | | |"),
> - PANIC_LINE(" // \\ \\ |_|"),
> - PANIC_LINE(" (| | ) _"),
> - PANIC_LINE(" /'\\_ _/`\\ (_)"),
> - PANIC_LINE(" \\___)=(___/"),
> - };
> -
> - static const size_t logo_ascii_lines = ARRAY_SIZE(logo_ascii);
> -
> - #if defined(CONFIG_LOGO) && !defined(MODULE)
> - static const struct linux_logo *logo_mono;
> -
> - static int drm_panic_setup_logo(void)
> - {
> - const struct linux_logo *logo = fb_find_logo(1);
> - const unsigned char *logo_data;
> - struct linux_logo *logo_dup;
> -
> - if (!logo || logo->type != LINUX_LOGO_MONO)
> - return 0;
> -
> - /* The logo is __init, so we must make a copy for later use */
> - logo_data = kmemdup(logo->data,
> - size_mul(DIV_ROUND_UP(logo->width, BITS_PER_BYTE), logo->height),
> - GFP_KERNEL);
> - if (!logo_data)
> - return -ENOMEM;
> -
> - logo_dup = kmemdup(logo, sizeof(*logo), GFP_KERNEL);
> - if (!logo_dup) {
> - kfree(logo_data);
> - return -ENOMEM;
> - }
> -
> - logo_dup->data = logo_data;
> - logo_mono = logo_dup;
> -
> - return 0;
> - }
> -
> - device_initcall(drm_panic_setup_logo);
> - #else
> - #define logo_mono ((const struct linux_logo *)NULL)
> - #endif
> -
> - /*
> - * Blit & Fill functions
> - */
> - static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect *clip,
> - const u8 *sbuf8, unsigned int spitch, unsigned int scale,
> - u32 fg_color)
> - {
> - unsigned int y, x;
> -
> - for (y = 0; y < drm_rect_height(clip); y++)
> - for (x = 0; x < drm_rect_width(clip); x++)
> - if (drm_draw_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
> - sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, fg_color);
> - }
> -
> - static void drm_panic_write_pixel16(void *vaddr, unsigned int offset, u16 color)
> - {
> - u16 *p = vaddr + offset;
> -
> - *p = color;
> - }
> -
> - static void drm_panic_write_pixel24(void *vaddr, unsigned int offset, u32 color)
> - {
> - u8 *p = vaddr + offset;
> -
> - *p++ = color & 0xff;
> - color >>= 8;
> - *p++ = color & 0xff;
> - color >>= 8;
> - *p = color & 0xff;
> - }
> -
> - /*
> - * Special case if the pixel crosses page boundaries
> - */
> - static void drm_panic_write_pixel24_xpage(void *vaddr, struct page *next_page,
> - unsigned int offset, u32 color)
> - {
> - u8 *vaddr2;
> - u8 *p = vaddr + offset;
> -
> - vaddr2 = kmap_local_page_try_from_panic(next_page);
> -
> - *p++ = color & 0xff;
> - color >>= 8;
> -
> - if (offset == PAGE_SIZE - 1)
> - p = vaddr2;
> -
> - *p++ = color & 0xff;
> - color >>= 8;
> -
> - if (offset == PAGE_SIZE - 2)
> - p = vaddr2;
> -
> - *p = color & 0xff;
> - kunmap_local(vaddr2);
> - }
> -
> - static void drm_panic_write_pixel32(void *vaddr, unsigned int offset, u32 color)
> - {
> - u32 *p = vaddr + offset;
> -
> - *p = color;
> - }
> -
> - static void drm_panic_write_pixel(void *vaddr, unsigned int offset, u32 color, unsigned int cpp)
> - {
> - switch (cpp) {
> - case 2:
> - drm_panic_write_pixel16(vaddr, offset, color);
> - break;
> - case 3:
> - drm_panic_write_pixel24(vaddr, offset, color);
> - break;
> - case 4:
> - drm_panic_write_pixel32(vaddr, offset, color);
> - break;
> - default:
> - pr_debug_once("Can't blit with pixel width %d\n", cpp);
> - }
> - }
> -
> - /*
> - * The scanout buffer pages are not mapped, so for each pixel,
> - * use kmap_local_page_try_from_panic() to map the page, and write the pixel.
> - * Try to keep the map from the previous pixel, to avoid too much map/unmap.
> - */
> - static void drm_panic_blit_page(struct page **pages, unsigned int dpitch,
> - unsigned int cpp, const u8 *sbuf8,
> - unsigned int spitch, struct drm_rect *clip,
> - unsigned int scale, u32 fg32)
> - {
> - unsigned int y, x;
> - unsigned int page = ~0;
> - unsigned int height = drm_rect_height(clip);
> - unsigned int width = drm_rect_width(clip);
> - void *vaddr = NULL;
> -
> - for (y = 0; y < height; y++) {
> - for (x = 0; x < width; x++) {
> - if (drm_draw_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) {
> - unsigned int new_page;
> - unsigned int offset;
> -
> - offset = (y + clip->y1) * dpitch + (x + clip->x1) * cpp;
> - new_page = offset >> PAGE_SHIFT;
> - offset = offset % PAGE_SIZE;
> - if (new_page != page) {
> - if (!pages[new_page])
> - continue;
> - if (vaddr)
> - kunmap_local(vaddr);
> - page = new_page;
> - vaddr = kmap_local_page_try_from_panic(pages[page]);
> - }
> - if (!vaddr)
> - continue;
> -
> - // Special case for 24bit, as a pixel might cross page boundaries
> - if (cpp == 3 && offset + 3 > PAGE_SIZE)
> - drm_panic_write_pixel24_xpage(vaddr, pages[page + 1],
> - offset, fg32);
> - else
> - drm_panic_write_pixel(vaddr, offset, fg32, cpp);
> - }
> - }
> - }
> - if (vaddr)
> - kunmap_local(vaddr);
> - }
> -
> - /*
> - * drm_panic_blit - convert a monochrome image to a linear framebuffer
> - * @sb: destination scanout buffer
> - * @clip: destination rectangle
> - * @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
> - * @spitch: source pitch in bytes
> - * @scale: integer scale, source buffer is scale time smaller than destination
> - * rectangle
> - * @fg_color: foreground color, in destination format
> - *
> - * This can be used to draw a font character, which is a monochrome image, to a
> - * framebuffer in other supported format.
> - */
> - static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
> - const u8 *sbuf8, unsigned int spitch,
> - unsigned int scale, u32 fg_color)
> -
> - {
> - struct iosys_map map;
> -
> - if (sb->set_pixel)
> - return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, scale, fg_color);
> -
> - if (sb->pages)
> - return drm_panic_blit_page(sb->pages, sb->pitch[0], sb->format->cpp[0],
> - sbuf8, spitch, clip, scale, fg_color);
> -
> - map = sb->map[0];
> - iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]);
> -
> - switch (sb->format->cpp[0]) {
> - case 2:
> - drm_draw_blit16(&map, sb->pitch[0], sbuf8, spitch,
> - drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
> - break;
> - case 3:
> - drm_draw_blit24(&map, sb->pitch[0], sbuf8, spitch,
> - drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
> - break;
> - case 4:
> - drm_draw_blit32(&map, sb->pitch[0], sbuf8, spitch,
> - drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
> - break;
> - default:
> - WARN_ONCE(1, "Can't blit with pixel width %d\n", sb->format->cpp[0]);
> - }
> - }
> -
> - static void drm_panic_fill_pixel(struct drm_scanout_buffer *sb,
> - struct drm_rect *clip,
> - u32 color)
> - {
> - unsigned int y, x;
> -
> - for (y = 0; y < drm_rect_height(clip); y++)
> - for (x = 0; x < drm_rect_width(clip); x++)
> - sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, color);
> - }
> -
> - static void drm_panic_fill_page(struct page **pages, unsigned int dpitch,
> - unsigned int cpp, struct drm_rect *clip,
> - u32 color)
> - {
> - unsigned int y, x;
> - unsigned int page = ~0;
> - void *vaddr = NULL;
> -
> - for (y = clip->y1; y < clip->y2; y++) {
> - for (x = clip->x1; x < clip->x2; x++) {
> - unsigned int new_page;
> - unsigned int offset;
> -
> - offset = y * dpitch + x * cpp;
> - new_page = offset >> PAGE_SHIFT;
> - offset = offset % PAGE_SIZE;
> - if (new_page != page) {
> - if (vaddr)
> - kunmap_local(vaddr);
> - page = new_page;
> - vaddr = kmap_local_page_try_from_panic(pages[page]);
> - }
> - if (!vaddr)
> - continue;
> -
> - // Special case for 24bit, as a pixel might cross page boundaries
> - if (cpp == 3 && offset + 3 > PAGE_SIZE)
> - drm_panic_write_pixel24_xpage(vaddr, pages[page + 1],
> - offset, color);
> - else
> - drm_panic_write_pixel(vaddr, offset, color, cpp);
> - }
> - }
> - if (vaddr)
> - kunmap_local(vaddr);
> - }
> -
> - /*
> - * drm_panic_fill - Fill a rectangle with a color
> - * @sb: destination scanout buffer
> - * @clip: destination rectangle
> - * @color: foreground color, in destination format
> - *
> - * Fill a rectangle with a color, in a linear framebuffer.
> - */
> - static void drm_panic_fill(struct drm_scanout_buffer *sb, struct drm_rect *clip,
> - u32 color)
> - {
> - struct iosys_map map;
> -
> - if (sb->set_pixel)
> - return drm_panic_fill_pixel(sb, clip, color);
> -
> - if (sb->pages)
> - return drm_panic_fill_page(sb->pages, sb->pitch[0], sb->format->cpp[0],
> - clip, color);
> -
> - map = sb->map[0];
> - iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]);
> -
> - switch (sb->format->cpp[0]) {
> - case 2:
> - drm_draw_fill16(&map, sb->pitch[0], drm_rect_height(clip),
> - drm_rect_width(clip), color);
> - break;
> - case 3:
> - drm_draw_fill24(&map, sb->pitch[0], drm_rect_height(clip),
> - drm_rect_width(clip), color);
> - break;
> - case 4:
> - drm_draw_fill32(&map, sb->pitch[0], drm_rect_height(clip),
> - drm_rect_width(clip), color);
> - break;
> - default:
> - WARN_ONCE(1, "Can't fill with pixel width %d\n", sb->format->cpp[0]);
> - }
> - }
> -
> - static unsigned int get_max_line_len(const struct drm_panic_line *lines, int len)
> - {
> - int i;
> - unsigned int max = 0;
> -
> - for (i = 0; i < len; i++)
> - max = max(lines[i].len, max);
> - return max;
> - }
> -
> - /*
> - * Draw a text in a rectangle on a framebuffer. The text is truncated if it overflows the rectangle
> - */
> - static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
> - const struct font_desc *font,
> - const struct drm_panic_line *msg,
> - unsigned int msg_lines,
> - bool centered,
> - struct drm_rect *clip,
> - u32 color)
> - {
> - int i, j;
> - const u8 *src;
> - size_t font_pitch = DIV_ROUND_UP(font->width, 8);
> - struct drm_rect rec;
> -
> - msg_lines = min(msg_lines, drm_rect_height(clip) / font->height);
> - for (i = 0; i < msg_lines; i++) {
> - size_t line_len = min(msg[i].len, drm_rect_width(clip) / font->width);
> -
> - rec.y1 = clip->y1 + i * font->height;
> - rec.y2 = rec.y1 + font->height;
> - rec.x1 = clip->x1;
> -
> - if (centered)
> - rec.x1 += (drm_rect_width(clip) - (line_len * font->width)) / 2;
> -
> - for (j = 0; j < line_len; j++) {
> - src = font_data_glyph_buf(font->data, font->width, font->height,
> - (unsigned char)msg[i].txt[j]);
> - rec.x2 = rec.x1 + font->width;
> - if (src)
> - drm_panic_blit(sb, &rec, src, font_pitch, 1, color);
> - rec.x1 += font->width;
> - }
> - }
> - }
> -
> - static void drm_panic_logo_rect(struct drm_rect *rect, const struct font_desc *font)
> - {
> - if (logo_mono) {
> - drm_rect_init(rect, 0, 0, logo_mono->width, logo_mono->height);
> - } else {
> - int logo_width = get_max_line_len(logo_ascii, logo_ascii_lines) * font->width;
> -
> - drm_rect_init(rect, 0, 0, logo_width, logo_ascii_lines * font->height);
> - }
> - }
> -
> - static void drm_panic_logo_draw(struct drm_scanout_buffer *sb, struct drm_rect *rect,
> - const struct font_desc *font, u32 fg_color)
> - {
> - if (rect->x2 > sb->width || rect->y2 > sb->height)
> - return;
> -
> - if (logo_mono)
> - drm_panic_blit(sb, rect, logo_mono->data,
> - DIV_ROUND_UP(drm_rect_width(rect), 8), 1, fg_color);
> - else
> - draw_txt_rectangle(sb, font, logo_ascii, logo_ascii_lines, false, rect,
> - fg_color);
> - }
> -
> - static void draw_panic_screen_user(struct drm_scanout_buffer *sb)
> - {
> - u32 fg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR,
> - sb->format->format);
> - u32 bg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR,
> - sb->format->format);
> - const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
> - struct drm_rect r_screen, r_logo, r_msg;
> - unsigned int msg_width, msg_height;
> -
> - if (!font)
> - return;
> -
> - r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
> - drm_panic_logo_rect(&r_logo, font);
> -
> - msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
> - msg_height = min(panic_msg_lines * font->height, sb->height);
> - r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
> -
> - /* Center the panic message */
> - drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2, (sb->height - r_msg.y2) / 2);
> -
> - /* Fill with the background color, and draw text on top */
> - drm_panic_fill(sb, &r_screen, bg_color);
> -
> - if (!drm_rect_overlap(&r_logo, &r_msg))
> - drm_panic_logo_draw(sb, &r_logo, font, fg_color);
> -
> - draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
> - }
> -
> - /*
> - * Draw one line of kmsg, and handle wrapping if it won't fit in the screen width.
> - * Return the y-offset of the next line.
> - */
> - static int draw_line_with_wrap(struct drm_scanout_buffer *sb, const struct font_desc *font,
> - struct drm_panic_line *line, int yoffset, u32 fg_color)
> - {
> - int chars_per_row = sb->width / font->width;
> - struct drm_rect r_txt = DRM_RECT_INIT(0, yoffset, sb->width, font->height);
> - struct drm_panic_line line_wrap;
> -
> - if (line->len > chars_per_row) {
> - line_wrap.len = line->len % chars_per_row;
> - line_wrap.txt = line->txt + line->len - line_wrap.len;
> - draw_txt_rectangle(sb, font, &line_wrap, 1, false, &r_txt, fg_color);
> - r_txt.y1 -= font->height;
> - if (r_txt.y1 < 0)
> - return r_txt.y1;
> - while (line_wrap.txt > line->txt) {
> - line_wrap.txt -= chars_per_row;
> - line_wrap.len = chars_per_row;
> - draw_txt_rectangle(sb, font, &line_wrap, 1, false, &r_txt, fg_color);
> - r_txt.y1 -= font->height;
> - if (r_txt.y1 < 0)
> - return r_txt.y1;
> - }
> - } else {
> - draw_txt_rectangle(sb, font, line, 1, false, &r_txt, fg_color);
> - r_txt.y1 -= font->height;
> - }
> - return r_txt.y1;
> - }
> -
> - /*
> - * Draw the kmsg buffer to the screen, starting from the youngest message at the bottom,
> - * and going up until reaching the top of the screen.
> - */
> - static void draw_panic_screen_kmsg(struct drm_scanout_buffer *sb)
> - {
> - u32 fg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR,
> - sb->format->format);
> - u32 bg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR,
> - sb->format->format);
> - const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
> - struct drm_rect r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
> - struct kmsg_dump_iter iter;
> - /* the size printk formats one record into, too big for the stack */
> - static char kmsg_buf[2048];
> - size_t kmsg_len;
> - struct drm_panic_line line;
> - int yoffset;
> -
> - if (!font || font->width > sb->width)
> - return;
> -
> - yoffset = sb->height - font->height - (sb->height % font->height) / 2;
> -
> - /* Fill with the background color, and draw text on top */
> - drm_panic_fill(sb, &r_screen, bg_color);
> -
> - kmsg_dump_rewind(&iter);
> - while (yoffset >= 0 && kmsg_dump_get_buffer(&iter, false, kmsg_buf,
> - sizeof(kmsg_buf), &kmsg_len)) {
> - char *start;
> - char *end;
> -
> - /* a record that does not fit comes back empty, every time */
> - if (!kmsg_len)
> - break;
> -
> - /* ignore terminating NUL and newline */
> - start = kmsg_buf + kmsg_len - 2;
> - end = kmsg_buf + kmsg_len - 1;
> - while (start > kmsg_buf && yoffset >= 0) {
> - while (start > kmsg_buf && *start != '\n')
> - start--;
> - /* don't count the newline character */
> - line.txt = start + (start == kmsg_buf ? 0 : 1);
> - line.len = end - line.txt;
> -
> - yoffset = draw_line_with_wrap(sb, font, &line, yoffset, fg_color);
> - end = start;
> - start--;
> - }
> - }
> - }
> -
> #if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
> - /*
> - * It is unwise to allocate memory in the panic callback, so the buffers are
> - * pre-allocated. Only 2 buffers and the zlib workspace are needed.
> - * Two buffers are enough, using the following buffer usage:
> - * 1) kmsg messages are dumped in buffer1
> - * 2) kmsg is zlib-compressed into buffer2
> - * 3) compressed kmsg is encoded as QR-code Numeric stream in buffer1
> - * 4) QR-code image is generated in buffer2
> - * The Max QR code size is V40, 177x177, 4071 bytes for image, 2956 bytes for
> - * data segments.
> - *
> - * Typically, ~7500 bytes of kmsg, are compressed into 2800 bytes, which fits in
> - * a V40 QR-code (177x177).
> - *
> - * If CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL is not set, the kmsg data will be put
> - * directly in the QR code.
> - * 1) kmsg messages are dumped in buffer1
> - * 2) kmsg message is encoded as byte stream in buffer2
> - * 3) QR-code image is generated in buffer1
> - */
> -
> static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION;
> module_param(panic_qr_version, uint, 0644);
> MODULE_PARM_DESC(panic_qr_version, "maximum version (size) of the QR code");
> -
> - #define MAX_QR_DATA 2956
> - #define MAX_ZLIB_RATIO 3
> - #define QR_BUFFER1_SIZE (MAX_ZLIB_RATIO * MAX_QR_DATA) /* Must also be > 4071 */
> - #define QR_BUFFER2_SIZE 4096
> - #define QR_MARGIN 4 /* 4 modules of foreground color around the qr code */
> -
> - /* Compression parameters */
> - #define COMPR_LEVEL 6
> - #define WINDOW_BITS 12
> - #define MEM_LEVEL 4
> -
> - static char *qrbuf1;
> - static char *qrbuf2;
> - static struct z_stream_s stream;
> -
> - static void __init drm_panic_qr_init(void)
> - {
> - qrbuf1 = kmalloc(QR_BUFFER1_SIZE, GFP_KERNEL);
> - qrbuf2 = kmalloc(QR_BUFFER2_SIZE, GFP_KERNEL);
> - stream.workspace = kmalloc(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
> - GFP_KERNEL);
> - }
> -
> - static void drm_panic_qr_exit(void)
> - {
> - kfree(qrbuf1);
> - qrbuf1 = NULL;
> - kfree(qrbuf2);
> - qrbuf2 = NULL;
> - kfree(stream.workspace);
> - stream.workspace = NULL;
> - }
> -
> - static int drm_panic_get_qr_code_url(u8 **qr_image)
> - {
> - struct kmsg_dump_iter iter;
> - char url[256];
> - size_t kmsg_len, max_kmsg_size;
> - char *kmsg;
> - int max_qr_data_size, url_len;
> -
> - url_len = snprintf(url, sizeof(url), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&z=",
> - utsname()->machine, utsname()->release);
> -
> - max_qr_data_size = drm_panic_qr_max_data_size(panic_qr_version, url_len);
> - max_kmsg_size = min(MAX_ZLIB_RATIO * max_qr_data_size, QR_BUFFER1_SIZE);
> -
> - /* get kmsg to buffer 1 */
> - kmsg_dump_rewind(&iter);
> - kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
> -
> - if (!kmsg_len)
> - return -ENODATA;
> - kmsg = qrbuf1;
> -
> - try_again:
> - if (zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
> - MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
> - return -EINVAL;
> -
> - stream.next_in = kmsg;
> - stream.avail_in = kmsg_len;
> - stream.total_in = 0;
> - stream.next_out = qrbuf2;
> - stream.avail_out = QR_BUFFER2_SIZE;
> - stream.total_out = 0;
> -
> - if (zlib_deflate(&stream, Z_FINISH) != Z_STREAM_END)
> - return -EINVAL;
> -
> - if (zlib_deflateEnd(&stream) != Z_OK)
> - return -EINVAL;
> -
> - if (stream.total_out > max_qr_data_size) {
> - /* too much data for the QR code, so skip the first line and try again */
> - kmsg = strchr(kmsg, '\n');
> - if (!kmsg)
> - return -EINVAL;
> - /* skip the first \n */
> - kmsg += 1;
> - kmsg_len = strlen(kmsg);
> - goto try_again;
> - }
> - *qr_image = qrbuf2;
> -
> - /* generate qr code image in buffer2 */
> - return drm_panic_qr_generate(url, qrbuf2, stream.total_out, QR_BUFFER2_SIZE,
> - qrbuf1, QR_BUFFER1_SIZE);
> - }
> -
> - static int drm_panic_get_qr_code_raw(u8 **qr_image)
> - {
> - struct kmsg_dump_iter iter;
> - size_t kmsg_len;
> - size_t max_kmsg_size = min(drm_panic_qr_max_data_size(panic_qr_version, 0),
> - QR_BUFFER1_SIZE);
> -
> - kmsg_dump_rewind(&iter);
> - kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
> - if (!kmsg_len)
> - return -ENODATA;
> -
> - *qr_image = qrbuf1;
> - return drm_panic_qr_generate(NULL, qrbuf1, kmsg_len, QR_BUFFER1_SIZE,
> - qrbuf2, QR_BUFFER2_SIZE);
> - }
> -
> - static int drm_panic_get_qr_code(u8 **qr_image)
> - {
> - if (strlen(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) > 0)
> - return drm_panic_get_qr_code_url(qr_image);
> - else
> - return drm_panic_get_qr_code_raw(qr_image);
> - }
> -
> - /*
> - * Draw the panic message at the center of the screen, with a QR Code
> - */
> - static int _draw_panic_screen_qr_code(struct drm_scanout_buffer *sb)
> - {
> - u32 fg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR,
> - sb->format->format);
> - u32 bg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR,
> - sb->format->format);
> - const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
> - struct drm_rect r_screen, r_logo, r_msg, r_qr, r_qr_canvas;
> - unsigned int max_qr_size, scale;
> - unsigned int msg_width, msg_height;
> - int qr_width, qr_canvas_width, qr_pitch, v_margin;
> - u8 *qr_image;
> -
> - if (!font || !qrbuf1 || !qrbuf2 || !stream.workspace)
> - return -ENOMEM;
> -
> - r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
> -
> - drm_panic_logo_rect(&r_logo, font);
> -
> - msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
> - msg_height = min(panic_msg_lines * font->height, sb->height);
> - r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
> -
> - max_qr_size = min(3 * sb->width / 4, 3 * sb->height / 4);
> -
> - qr_width = drm_panic_get_qr_code(&qr_image);
> - if (qr_width <= 0)
> - return -ENOSPC;
> -
> - qr_canvas_width = qr_width + QR_MARGIN * 2;
> - scale = max_qr_size / qr_canvas_width;
> - /* QR code is not readable if not scaled at least by 2 */
> - if (scale < 2)
> - return -ENOSPC;
> -
> - pr_debug("QR width %d and scale %d\n", qr_width, scale);
> - r_qr_canvas = DRM_RECT_INIT(0, 0, qr_canvas_width * scale, qr_canvas_width * scale);
> -
> - v_margin = sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg);
> - if (v_margin < 0)
> - return -ENOSPC;
> - v_margin /= 5;
> -
> - drm_rect_translate(&r_qr_canvas, (sb->width - r_qr_canvas.x2) / 2, 2 * v_margin);
> - r_qr = DRM_RECT_INIT(r_qr_canvas.x1 + QR_MARGIN * scale, r_qr_canvas.y1 + QR_MARGIN * scale,
> - qr_width * scale, qr_width * scale);
> -
> - /* Center the panic message */
> - drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2,
> - 3 * v_margin + drm_rect_height(&r_qr_canvas));
> -
> - /* Fill with the background color, and draw text on top */
> - drm_panic_fill(sb, &r_screen, bg_color);
> -
> - if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr_canvas))
> - drm_panic_logo_draw(sb, &r_logo, font, fg_color);
> -
> - draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
> -
> - /* Draw the qr code */
> - qr_pitch = DIV_ROUND_UP(qr_width, 8);
> - drm_panic_fill(sb, &r_qr_canvas, fg_color);
> - drm_panic_fill(sb, &r_qr, bg_color);
> - drm_panic_blit(sb, &r_qr, qr_image, qr_pitch, scale, fg_color);
> - return 0;
> - }
> -
> - static void draw_panic_screen_qr_code(struct drm_scanout_buffer *sb)
> - {
> - if (_draw_panic_screen_qr_code(sb))
> - draw_panic_screen_user(sb);
> - }
> - #else
> - static void drm_panic_qr_init(void) {};
> - static void drm_panic_qr_exit(void) {};
> #endif
>
> - enum drm_panic_type {
> - DRM_PANIC_TYPE_KMSG,
> - DRM_PANIC_TYPE_USER,
> - DRM_PANIC_TYPE_QR,
> - };
> -
> static enum drm_panic_type drm_panic_type = -1;
>
> static const char *drm_panic_type_map[] = {
> @@@ -840,7 -66,7 +66,7 @@@ static int drm_panic_type_set(const cha
> unsigned int i;
>
> for (i = 0; i < ARRAY_SIZE(drm_panic_type_map); i++) {
> - if (!strcmp(val, drm_panic_type_map[i])) {
> + if (sysfs_streq(val, drm_panic_type_map[i])) {
> drm_panic_type = i;
> return 0;
> }
> @@@ -869,91 -95,34 +95,34 @@@ MODULE_PARM_DESC(panic_screen
> #endif
> CONFIG_DRM_PANIC_SCREEN "]");
>
> - /*
> - * drm_panic_is_format_supported()
> - * @format: a fourcc color code
> - * Returns: true if supported, false otherwise.
> - *
> - * Check if drm_panic will be able to use this color format.
> - */
> - static bool drm_panic_is_format_supported(const struct drm_format_info *format)
> - {
> - if (format->num_planes != 1)
> - return false;
> - return drm_draw_can_convert_from_xrgb8888(format->format);
> - }
> + #define drm_panic_trylock(dev, flags) \
> + raw_spin_trylock_irqsave(&(dev)->mode_config.panic_lock, flags)
>
> - static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
> + static void drm_panic_display_panic_screen(struct drm_plane *plane, const char *description)
> {
> - switch (drm_panic_type) {
> - case DRM_PANIC_TYPE_KMSG:
> - draw_panic_screen_kmsg(sb);
> - break;
> -
> - #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
> - case DRM_PANIC_TYPE_QR:
> - draw_panic_screen_qr_code(sb);
> - break;
> + #if defined(CONFIG_DRM_PANIC_FOREGROUND_COLOR)
> + u32 fg_color = CONFIG_DRM_PANIC_FOREGROUND_COLOR;
> + #else
> + u32 fg_color = 0x00ffffff;
> #endif
> -
> - case DRM_PANIC_TYPE_USER:
> - default:
> - draw_panic_screen_user(sb);
> - }
> - }
> -
> - static void drm_panic_set_description(const char *description)
> - {
> - u32 len;
> -
> - if (description) {
> - struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
> -
> - desc_line->txt = description;
> - len = strlen(description);
> - /* ignore the last newline character */
> - if (len && description[len - 1] == '\n')
> - len -= 1;
> - desc_line->len = len;
> - }
> - }
> -
> - static void drm_panic_clear_description(void)
> - {
> - struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
> -
> - desc_line->len = 0;
> - desc_line->txt = NULL;
> - }
> -
> - static void draw_panic_plane(struct drm_plane *plane, const char *description)
> - {
> - struct drm_scanout_buffer sb = { };
> - int ret;
> + #if defined(CONFIG_DRM_PANIC_BACKGROUND_COLOR)
> + u32 bg_color = CONFIG_DRM_PANIC_BACKGROUND_COLOR;
> + #else
> + u32 bg_color = 0x00000000;
> + #endif
> + #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
> + unsigned int qr_version = panic_qr_version;
> + #else
> + unsigned int qr_version = 0;
> + #endif
> + struct drm_device *dev = plane->dev;
> unsigned long flags;
>
> - if (!drm_panic_trylock(plane->dev, flags))
> - return;
> -
> - ret = plane->helper_private->get_scanout_buffer(plane, &sb);
> -
> - if (ret || !drm_panic_is_format_supported(sb.format))
> - goto unlock;
> -
> - /* One of these should be set, or it can't draw pixels */
> - if (!sb.set_pixel && !sb.pages && iosys_map_is_null(&sb.map[0]))
> - goto unlock;
> -
> - drm_panic_set_description(description);
> -
> - draw_panic_dispatch(&sb);
> - if (plane->helper_private->panic_flush)
> - plane->helper_private->panic_flush(plane);
> -
> - drm_panic_clear_description();
> -
> - unlock:
> - drm_panic_unlock(plane->dev, flags);
> + if (drm_panic_trylock(dev, flags)) {
> + plane->funcs->display_panic_screen(plane, description, drm_panic_type,
> + fg_color, bg_color, qr_version);
> + drm_panic_unlock(dev, flags);
> + }
> }
>
> static struct drm_plane *to_drm_plane(struct kmsg_dumper *kd)
> @@@ -966,10 -135,9 +135,9 @@@ static void drm_panic(struct kmsg_dumpe
> struct drm_plane *plane = to_drm_plane(dumper);
>
> if (detail->reason == KMSG_DUMP_PANIC)
> - draw_panic_plane(plane, detail->description);
> + drm_panic_display_panic_screen(plane, detail->description);
> }
>
> -
> /*
> * DEBUG FS, This is currently unsafe.
> * Create one file per plane, so it's possible to debug one plane at a time.
> @@@ -986,7 -154,7 +154,7 @@@ static ssize_t debugfs_trigger_write(st
> if (kstrtobool_from_user(user_buf, count, &run) == 0 && run) {
> struct drm_plane *plane = file->private_data;
>
> - draw_panic_plane(plane, "Test from debugfs");
> + drm_panic_display_panic_screen(plane, "Test from debugfs");
> }
> return count;
> }
> @@@ -1022,9 -190,13 +190,13 @@@ bool drm_panic_is_enabled(struct drm_de
> if (!dev->mode_config.num_total_plane)
> return false;
>
> - drm_for_each_plane(plane, dev)
> - if (plane->helper_private && plane->helper_private->get_scanout_buffer)
> - return true;
> + drm_for_each_plane(plane, dev) {
> + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> + continue;
> + if (!plane->funcs || !plane->funcs->display_panic_screen)
> + continue;
> + return true;
> + }
> return false;
> }
> EXPORT_SYMBOL(drm_panic_is_enabled);
> @@@ -1042,7 -214,9 +214,9 @@@ void drm_panic_register(struct drm_devi
> return;
>
> drm_for_each_plane(plane, dev) {
> - if (!plane->helper_private || !plane->helper_private->get_scanout_buffer)
> + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> + continue;
> + if (!plane->funcs || !plane->funcs->display_panic_screen)
> continue;
> plane->kmsg_panic.dump = drm_panic;
> plane->kmsg_panic.max_reason = KMSG_DUMP_PANIC;
> @@@ -1069,7 -243,9 +243,9 @@@ void drm_panic_unregister(struct drm_de
> return;
>
> drm_for_each_plane(plane, dev) {
> - if (!plane->helper_private || !plane->helper_private->get_scanout_buffer)
> + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> + continue;
> + if (!plane->funcs || !plane->funcs->display_panic_screen)
> continue;
> kmsg_dump_unregister(&plane->kmsg_panic);
> }
> @@@ -1085,17 -261,4 +261,4 @@@ void __init drm_panic_init(void
> CONFIG_DRM_PANIC_SCREEN);
> drm_panic_type = DRM_PANIC_TYPE_USER;
> }
> - drm_panic_qr_init();
> }
> -
> - /**
> - * drm_panic_exit() - Free the resources taken by drm_panic_exit()
> - */
> - void drm_panic_exit(void)
> - {
> - drm_panic_qr_exit();
> - }
> -
> - #ifdef CONFIG_DRM_KUNIT_TEST
> - #include "tests/drm_panic_test.c"
> - #endif
next prev parent reply other threads:[~2026-10-20 7:30 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 16:10 Mark Brown
2026-10-19 19:09 ` Devin Wittmayer
2026-10-20 9:52 ` Mark Brown
2026-10-20 7:30 ` Jocelyn Falempe [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-09-28 14:15 Mark Brown
2026-09-18 11:14 Mark Brown
2026-09-18 11:14 Mark Brown
2026-08-12 15:45 Mark Brown
2026-08-12 12:20 Mark Brown
2026-06-11 13:54 Mark Brown
2026-06-16 9:16 ` Geert Uytterhoeven
2026-03-20 14:17 Mark Brown
2026-03-20 15:39 ` Boris Brezillon
2026-04-08 17:26 ` Mark Brown
2026-04-09 7:47 ` Boris Brezillon
2026-03-18 14:36 Mark Brown
2026-03-18 15:49 ` Luca Ceresoli
2026-03-18 18:20 ` Cristian Ciocaltea
2026-01-05 2:21 Stephen Rothwell
2025-08-20 1:21 Stephen Rothwell
2025-08-20 10:30 ` Danilo Krummrich
2025-08-20 21:29 ` Stephen Rothwell
2025-07-18 4:41 Stephen Rothwell
2025-07-18 6:27 ` Thomas Zimmermann
2025-01-14 1:30 Stephen Rothwell
2023-11-22 0:29 Stephen Rothwell
2023-11-28 10:04 ` Geert Uytterhoeven
2023-09-28 2:05 Stephen Rothwell
2023-06-27 1:54 Stephen Rothwell
2023-07-11 1:17 ` Stephen Rothwell
2022-11-21 2:06 Stephen Rothwell
2022-07-11 2:47 Stephen Rothwell
2022-07-11 8:05 ` Christian König
2022-07-17 23:44 ` Stephen Rothwell
2022-07-19 7:35 ` Geert Uytterhoeven
2022-07-27 2:55 ` Stephen Rothwell
2022-07-27 3:24 ` Dave Airlie
2022-07-27 5:37 ` Stephen Rothwell
2022-03-18 0:55 Stephen Rothwell
2022-03-18 1:06 ` Stephen Rothwell
2021-12-22 3:50 Stephen Rothwell
2021-12-22 7:31 ` Christian König
2021-11-29 23:33 Stephen Rothwell
2021-11-30 8:58 ` Maxime Ripard
2021-11-30 20:35 ` Stephen Rothwell
2021-10-22 0:53 Stephen Rothwell
2021-06-17 1:42 Stephen Rothwell
2021-04-09 3:12 Stephen Rothwell
2021-03-18 1:02 Stephen Rothwell
2021-03-18 6:51 ` Tomi Valkeinen
2020-07-28 3:41 Stephen Rothwell
2020-05-01 3:45 Stephen Rothwell
2020-03-01 23:43 Stephen Rothwell
2019-09-15 21:18 Mark Brown
2019-09-16 5:29 ` Vasily Khoruzhick
2019-09-17 2:43 ` Qiang Yu
2019-08-26 3:06 Stephen Rothwell
2019-08-29 10:11 ` james qian wang (Arm Technology China)
2018-11-26 2:37 Stephen Rothwell
2018-03-08 0:47 Stephen Rothwell
2017-12-13 23:59 Stephen Rothwell
2017-01-17 0:59 Stephen Rothwell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4cb04699-c607-4f20-be66-0d8e21666af5@redhat.com \
--to=jfalempe@redhat.com \
--cc=airlied@redhat.com \
--cc=broonie@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-next@vger.kernel.org \
--cc=lucid_duck@justthetip.ca \
--cc=luyuantao@kylinos.cn \
--cc=simona.vetter@ffwll.ch \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®