From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C12C6233929; Mon, 24 Aug 2026 12:54:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.131 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787576084; cv=none; b=EpYaWGfliqBxYnoD4ArU9iLf7bzCrwykj142j4QdwDIV77Rz4eMo5Kapxr4qfWfW6TN2MTIOrI2aDEFb6q5imeGWr5opzfJWLx3ifrcpq2erqqRwD81Pfe395PhRFYRgVBfIfHsT5TO8SJjnUtK3e8DoOAIiUH/wmqy18t61q4E= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787576084; c=relaxed/simple; bh=V5IyK9zdH7ULfH5GFE3j9ifWq8g9hRw4JiPn9hV0kxw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ysz2rF82MXhE0WP9+ktsb33QiYp4UMce55mQW0B1DCEqXIXFkP2ui8pVAAQFGQoNgMzFgrTz2T4USzETLiomDRZnG+Nq8s21ihNnkn8vCeyDmPtETVpn4k723Ui/VzbbdcLDvLt9ZbBbnL3Hl5npyGoOpchLoGh3AEX66xCOKIc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de; spf=pass smtp.mailfrom=suse.de; arc=none smtp.client-ip=195.135.223.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.de Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 9BEDB1F43B; Mon, 24 Aug 2026 12:52:11 +0000 (UTC) Authentication-Results: smtp-out2.suse.de; none Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 04DB513411; Mon, 24 Aug 2026 12:52:10 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id KMqLO3o+jGpyNwAAD6G6ig (envelope-from ); Mon, 24 Aug 2026 12:52:10 +0000 From: Thomas Zimmermann To: jfalempe@redhat.com, javierm@redhat.com, airlied@gmail.com, simona@ffwll.ch, maarten.lankhorst@linux.intel.com, mripard@kernel.org, geert@linux-m68k.org, rdunlap@infradead.org Cc: dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org, amd-gfx@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-hyperv@vger.kernel.org, intel-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, nouveau@lists.freedesktop.org, linux-renesas-soc@vger.kernel.org, virtualization@lists.linux.dev, sashiko-reviews@lists.linux.dev, Thomas Zimmermann Subject: [PATCH v2 10/13] drm/panic: Display panic screen via per-plane callback Date: Mon, 24 Aug 2026 14:43:41 +0200 Message-ID: <20260824125201.218863-11-tzimmermann@suse.de> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260824125201.218863-1-tzimmermann@suse.de> References: <20260824125201.218863-1-tzimmermann@suse.de> Precedence: bulk X-Mailing-List: imx@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Spam-Flag: NO X-Spam-Score: -4.00 X-Spam-Level: X-Rspamd-Queue-Id: 9BEDB1F43B X-Rspamd-Server: rspamd1.dmz-prg2.suse.org X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Spamd-Result: default: False [-4.00 / 50.00]; REPLY(-4.00)[] X-Rspamd-Action: no action Add display_panic_screen to struct drm_plane_funcs. If set on a plane, register a panic handler for the plane from the DRM core's panic handling. Invoke this helper from the core to display a panic screen. The new callback replaces get_scanout_buffer as signal for panic support in a plane. Using get_scanout_buffer is now merely a detail of the implementation. This will also free struct drm_scanout_buffer for use cases besides panic handling. With display_panic_screen in place, rename draw_panic_plane() to drm_plane_helper_display_panic_screen() and make it available to DRM drivers via drm_panic_helper.h. Do not change the implementation or functionality of this code. drm_plane_helper_display_panic_screen() still supports kernel messages, user messages and QR codes on various color formats. Then update all drivers that implement panic support. Provide the initializer macro DRM_PANIC_PLANE_FUNCS that sets display_panic_screen to drm_plane_helper_display_panic_screen(). If panic handling has been disabled, it instead clears the callback. There's again no change in functionality. This logically splits panic handling into a set of entry points in the DRM code and a set of helper functions provided by drivers. The core invokes the driver's helper via callback, while the driver can tailor the implementation to its needs. Panic handling now works like most other interfaces in the DRM framework. Locking and state-handling happens in the DRM core or helpers. Drivers that receive a call to display_panic_screen can assume that no concurrent modeset takes place on the plane or its CRTC. Also update the documentation. Move information about locking and state guarantees from drm_panic_trylock() to display_panic_screen, where drivers authors can find it easily. Move information about the features of the current implementation to drm_panic_helper_display_panic_screen(). v2: - only consider planes with get_scanout_buffer (Sashiko) - set callback for planes create with drm_crtc_init() (Sashiko) - return errno code from display_panic_screen Signed-off-by: Thomas Zimmermann --- MAINTAINERS | 3 +- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 2 + drivers/gpu/drm/ast/ast_mode.c | 2 + drivers/gpu/drm/drm_modeset_helper.c | 2 + drivers/gpu/drm/drm_panic.c | 89 ++++++++++--------- drivers/gpu/drm/hyperv/hyperv_drm_modeset.c | 2 + drivers/gpu/drm/i915/display/i9xx_plane.c | 3 + .../drm/i915/display/skl_universal_plane.c | 4 + drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c | 2 + drivers/gpu/drm/mgag200/mgag200_drv.h | 4 +- drivers/gpu/drm/nouveau/dispnv50/wndw.c | 2 + .../gpu/drm/renesas/rcar-du/rcar_du_plane.c | 2 + .../drm/renesas/shmobile/shmob_drm_plane.c | 2 + drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 4 +- drivers/gpu/drm/sysfb/vesadrm.c | 1 + drivers/gpu/drm/tidss/tidss_plane.c | 2 + drivers/gpu/drm/tiny/bochs.c | 4 +- drivers/gpu/drm/virtio/virtgpu_plane.c | 2 + include/drm/drm_mode_config.h | 4 +- include/drm/drm_modeset_helper_vtables.h | 11 ++- include/drm/drm_panic.h | 49 +++------- include/drm/drm_panic_helper.h | 27 ++++++ include/drm/drm_plane.h | 57 ++++++++++++ 23 files changed, 191 insertions(+), 89 deletions(-) create mode 100644 include/drm/drm_panic_helper.h diff --git a/MAINTAINERS b/MAINTAINERS index 928b3ba23a76..472c5c48729d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9020,7 +9020,8 @@ F: drivers/gpu/drm/drm_draw.c F: drivers/gpu/drm/drm_draw_internal.h F: drivers/gpu/drm/drm_panic*.c F: drivers/gpu/drm/tests/drm_panic_test.c -F: include/drm/drm_panic* +F: include/drm/drm_panic.h +F: include/drm/drm_panic_helper.h DRM PANIC QR CODE M: Jocelyn Falempe diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 824ef3ce5de0..eadc22a255bb 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -28,6 +28,7 @@ #include #include "drm/drm_framebuffer.h" #include +#include #include #include #include @@ -2177,6 +2178,7 @@ static const struct drm_plane_funcs dm_plane_funcs = { .atomic_set_property = dm_atomic_plane_set_property, .atomic_get_property = dm_atomic_plane_get_property, #endif + DRM_PANIC_PLANE_FUNCS, }; int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index d5ed8c5c7925..ceebf9421100 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -652,6 +653,7 @@ static const struct drm_plane_funcs ast_primary_plane_funcs = { .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, DRM_GEM_SHADOW_PLANE_FUNCS, + DRM_PANIC_PLANE_FUNCS, }; static int ast_primary_plane_init(struct ast_device *ast) diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index e54584da4c3d..cca623eb23e5 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,7 @@ static const uint32_t safe_modeset_formats[] = { static const struct drm_plane_funcs primary_plane_funcs = { DRM_PLANE_NON_ATOMIC_FUNCS, + DRM_PANIC_PLANE_FUNCS, }; /** diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 7dbbcc1c219f..0fe9a0d67db3 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -42,32 +43,18 @@ 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. This is conflicting with fbcon, so you can only enable + * it when fbcon is disabled. 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 { @@ -817,12 +804,6 @@ 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[] = { @@ -936,21 +917,46 @@ static void drm_panic_clear_description(void) desc_line->txt = NULL; } -static void draw_panic_plane(struct drm_plane *plane, const char *description, - enum drm_panic_type panic_type, u32 fg_color, u32 bg_color, - unsigned int qr_version) +/** + * drm_plane_helper_display_panic_screen - Displays a panic screen according to the given settings + * @plane: the DRM plane to display to + * @description: error message to display + * @panic_type: type of panic screen + * @fg_color: text foreground color + * @bg_color: text background color + * @qr_version: version of the QR code, if any + * + * This helper display a panic screen on common primary planes. The panic + * screen can either display a kernel message, a user message or a QR code. + * + * The helper uses struct drm_plane_helper_funcs.get_scanout_buffer, where + * the plane can provide a scanout buffer that the panic handler can draw to. + * Currently only linear buffer and a few color formats are supported. + * + * Optionally the plane can also provide a &drm_plane_helper_funcs.panic_flush + * callback, which the DRM panic handler calls after drawing to send additional + * commands to the hardware to make the scanout buffer visible. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_plane_helper_display_panic_screen(struct drm_plane *plane, const char *description, + enum drm_panic_type panic_type, + u32 fg_color, u32 bg_color, unsigned int qr_version) { struct drm_scanout_buffer sb = { }; int ret; ret = plane->helper_private->get_scanout_buffer(plane, &sb); + if (ret) + return ret; - if (ret || !drm_panic_is_format_supported(sb.format)) - return; + if (!drm_panic_is_format_supported(sb.format)) + return -EINVAL; /* 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])) - return; + return -EINVAL; drm_panic_set_description(description); @@ -965,7 +971,10 @@ static void draw_panic_plane(struct drm_plane *plane, const char *description, } drm_panic_clear_description(); + + return ret; } +EXPORT_SYMBOL(drm_plane_helper_display_panic_screen); static void drm_panic_display_panic_screen(struct drm_plane *plane, const char *description) { @@ -988,8 +997,8 @@ static void drm_panic_display_panic_screen(struct drm_plane *plane, const char * unsigned long flags; if (drm_panic_trylock(dev, flags)) { - draw_panic_plane(plane, description, drm_panic_type, - fg_color, bg_color, qr_version); + plane->funcs->display_panic_screen(plane, description, drm_panic_type, + fg_color, bg_color, qr_version); drm_panic_unlock(dev, flags); } } @@ -1060,7 +1069,7 @@ bool drm_panic_is_enabled(struct drm_device *dev) return false; drm_for_each_plane(plane, dev) - if (plane->helper_private && plane->helper_private->get_scanout_buffer) + if (plane->funcs && plane->funcs->display_panic_screen) return true; return false; } @@ -1081,7 +1090,7 @@ void drm_panic_register(struct drm_device *dev) drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) continue; - if (!plane->helper_private || !plane->helper_private->get_scanout_buffer) + if (!plane->funcs || !plane->funcs->display_panic_screen) continue; plane->kmsg_panic.dump = drm_panic; plane->kmsg_panic.max_reason = KMSG_DUMP_PANIC; diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c index 1855749c1e41..3bf228ef97ff 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_modeset.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -237,6 +238,7 @@ static const struct drm_plane_funcs hv_drm_plane_funcs = { .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, DRM_GEM_SHADOW_PLANE_FUNCS, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_encoder_funcs hv_drm_simple_encoder_funcs_cleanup = { diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index df6da1c6a359..0902b17d0269 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "i9xx_plane.h" @@ -887,6 +888,7 @@ static const struct drm_plane_funcs i965_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = i965_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_plane_funcs i8xx_plane_funcs = { @@ -897,6 +899,7 @@ static const struct drm_plane_funcs i8xx_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = i8xx_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static void i9xx_disable_tiling(struct intel_plane *plane) diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 07a683293352..45e8379d93d4 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -2707,6 +2708,7 @@ static const struct drm_plane_funcs skl_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = skl_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_plane_funcs icl_plane_funcs = { @@ -2717,6 +2719,7 @@ static const struct drm_plane_funcs icl_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = icl_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static const struct drm_plane_funcs tgl_plane_funcs = { @@ -2727,6 +2730,7 @@ static const struct drm_plane_funcs tgl_plane_funcs = { .atomic_destroy_state = intel_plane_destroy_state, .format_mod_supported = tgl_plane_format_mod_supported, .format_mod_supported_async = intel_plane_format_mod_supported_async, + DRM_PANIC_PLANE_FUNCS, }; static void diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c index c7ec09e557c1..377db7cea726 100644 --- a/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include