From nobody Mon Feb 9 23:04:25 2026 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.223.130]) (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 1748A32C92D for ; Fri, 7 Nov 2025 14:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762525587; cv=none; b=rdX3kN6ntowIycCpiZH1Oe7PfuIWMT69ebb2aSoz3cg1tb8uWdOCTJD7C/V6HQunAu9ji1BQZ1cLtpqg1N7ewjqZhOXjf4B7W0/ji/ta7Ihx8oW7sbZ34pCB8VhaC5/6TEvDIMs748oTf7ltDjIlqD56oylj13rWjdPEGkVV7IE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762525587; c=relaxed/simple; bh=/rq71HN0ZxpX43JpZGL283761bbNjY0QyPG/ZJcbU2g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GifsQN72XJ1kTGHHvfHZiR9+x5L0lmJsnwdHxMp4vWu4UlAt4w3YbvWHPOoZbkovy+PbaAuYS0Yh/Hvw3svqSz4QnVM9A9u3odJ8Pun+YKplEG92+W3eE7Hbmi3JfduJg7Qad79l1F2e0q/36/89PnDLuJ+Jrd8hZDhasgcJUwY= 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; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=zU4ycOPN; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=6LUcXeH6; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=zU4ycOPN; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=6LUcXeH6; arc=none smtp.client-ip=195.135.223.130 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 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="zU4ycOPN"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="6LUcXeH6"; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="zU4ycOPN"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="6LUcXeH6" Received: from imap1.dmz-prg2.suse.org (unknown [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-out1.suse.de (Postfix) with ESMTPS id 37065211F7; Fri, 7 Nov 2025 14:26:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1762525577; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1IJ8SMZfglc9SeMZthZTk39PHOnrpfNId5Z49aJR2fc=; b=zU4ycOPNiDpGRoK1ELlDpTcy4DcgpLgnwLT4atdGnDCo1kkk5BJXW+/ia+TPI9wbw97Tj2 dE6M5fTt3UR1a8sjswkx96J4Np5UYddCRoBpEZYmAUhnVNCpkWX8MaJoE1fmHgAoZ9OSqi SK29DtXiC+FNkLsWhUTGlpQASBLIg9Q= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1762525577; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1IJ8SMZfglc9SeMZthZTk39PHOnrpfNId5Z49aJR2fc=; b=6LUcXeH62ZYOkZyCU/3ublX5PYaPrgkLwOF1DrAyFDtiubcpfUxMb4u0BX9Dwf3gbkFQbR wqA6w0yIfeXmrtBQ== Authentication-Results: smtp-out1.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1762525577; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1IJ8SMZfglc9SeMZthZTk39PHOnrpfNId5Z49aJR2fc=; b=zU4ycOPNiDpGRoK1ELlDpTcy4DcgpLgnwLT4atdGnDCo1kkk5BJXW+/ia+TPI9wbw97Tj2 dE6M5fTt3UR1a8sjswkx96J4Np5UYddCRoBpEZYmAUhnVNCpkWX8MaJoE1fmHgAoZ9OSqi SK29DtXiC+FNkLsWhUTGlpQASBLIg9Q= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1762525577; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1IJ8SMZfglc9SeMZthZTk39PHOnrpfNId5Z49aJR2fc=; b=6LUcXeH62ZYOkZyCU/3ublX5PYaPrgkLwOF1DrAyFDtiubcpfUxMb4u0BX9Dwf3gbkFQbR wqA6w0yIfeXmrtBQ== 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 D966B1395F; Fri, 7 Nov 2025 14:26:16 +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 iJvVM4gBDmkaLgAAD6G6ig (envelope-from ); Fri, 07 Nov 2025 14:26:16 +0000 From: Thomas Zimmermann To: jfalempe@redhat.com, javierm@redhat.com, simona@ffwll.ch, airlied@gmail.com, mripard@kernel.org, maarten.lankhorst@linux.intel.com, gregkh@linuxfoundation.org, jirislaby@kernel.org Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, Thomas Zimmermann Subject: [PATCH 2/3] drm/client: Support emergency restore via sysrq for all clients Date: Fri, 7 Nov 2025 15:19:26 +0100 Message-ID: <20251107142612.467817-3-tzimmermann@suse.de> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251107142612.467817-1-tzimmermann@suse.de> References: <20251107142612.467817-1-tzimmermann@suse.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Spam-Level: X-Spamd-Result: default: False [-2.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; NEURAL_HAM_LONG(-1.00)[-1.000]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; TO_MATCH_ENVRCPT_ALL(0.00)[]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; FROM_HAS_DN(0.00)[]; RCPT_COUNT_TWELVE(0.00)[12]; MIME_TRACE(0.00)[0:+]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo,suse.de:email,suse.de:mid]; FUZZY_RATELIMITED(0.00)[rspamd.com]; FROM_EQ_ENVFROM(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; FREEMAIL_TO(0.00)[redhat.com,ffwll.ch,gmail.com,kernel.org,linux.intel.com,linuxfoundation.org]; RCVD_TLS_ALL(0.00)[]; TO_DN_SOME(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; FREEMAIL_ENVRCPT(0.00)[gmail.com] X-Spam-Flag: NO X-Spam-Score: -2.80 Content-Type: text/plain; charset="utf-8" Move the sysrq functionality from DRM fb-helpers to the DRM device and in-kernel clients, so that all it becomes available on all clients. DRM fbdev helpers support emergency restoration of the console output via a special key combination. Press SysRq+v to replace the current compositor with the kernel's output on the text-mode console. This allows users to see the log messages during system emergencies. By moving the functionality from fb-helper to DRM devices, any in-kernel client can serve as emergency output. This can be used to bring up drm_log, for example. Each DRM device registers itself to the list possible sysrq handlers. On receiving SysRq+v, the DRM core goes over all registered devices and restores an in-kernel DRM client for each of them. See Documentation/admin-guide/sysrq.rst on how to invoke SysRq. Switch VTs to bring back the user-space compositor. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_client.c | 1 + drivers/gpu/drm/drm_client_sysrq.c | 65 ++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 3 ++ drivers/gpu/drm/drm_fb_helper.c | 45 +-------------------- drivers/gpu/drm/drm_internal.h | 11 +++++ include/drm/drm_device.h | 8 ++++ 7 files changed, 91 insertions(+), 45 deletions(-) create mode 100644 drivers/gpu/drm/drm_client_sysrq.c diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index c2672f369aed..9901534948e5 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -76,7 +76,8 @@ drm-y :=3D \ drm-$(CONFIG_DRM_CLIENT) +=3D \ drm_client.o \ drm_client_event.o \ - drm_client_modeset.o + drm_client_modeset.o \ + drm_client_sysrq.o drm-$(CONFIG_DRM_LIB_RANDOM) +=3D lib/drm_random.o drm-$(CONFIG_COMPAT) +=3D drm_ioc32.o drm-$(CONFIG_DRM_PANEL) +=3D drm_panel.o diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 504ec5bdfa2c..a82d741e6630 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -11,6 +11,7 @@ #include =20 #include +#include #include #include #include diff --git a/drivers/gpu/drm/drm_client_sysrq.c b/drivers/gpu/drm/drm_clien= t_sysrq.c new file mode 100644 index 000000000000..eea660096f1b --- /dev/null +++ b/drivers/gpu/drm/drm_client_sysrq.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT + +#include + +#include +#include +#include + +#include "drm_internal.h" + +#ifdef CONFIG_MAGIC_SYSRQ +static LIST_HEAD(drm_client_sysrq_dev_list); +static DEFINE_MUTEX(drm_client_sysrq_dev_lock); + +/* emergency restore, don't bother with error reporting */ +static void drm_client_sysrq_restore_work_fn(struct work_struct *ignored) +{ + struct drm_device *dev; + + guard(mutex)(&drm_client_sysrq_dev_lock); + + list_for_each_entry(dev, &drm_client_sysrq_dev_list, client_sysrq_list) { + if (dev->switch_power_state =3D=3D DRM_SWITCH_POWER_OFF) + continue; + + drm_client_dev_restore(dev, true); + } +} + +static DECLARE_WORK(drm_client_sysrq_restore_work, drm_client_sysrq_restor= e_work_fn); + +static void drm_client_sysrq_restore_handler(u8 ignored) +{ + schedule_work(&drm_client_sysrq_restore_work); +} + +static const struct sysrq_key_op drm_client_sysrq_restore_op =3D { + .handler =3D drm_client_sysrq_restore_handler, + .help_msg =3D "force-fb(v)", + .action_msg =3D "Restore framebuffer console", +}; + +void drm_client_sysrq_register(struct drm_device *dev) +{ + guard(mutex)(&drm_client_sysrq_dev_lock); + + if (list_empty(&drm_client_sysrq_dev_list)) + register_sysrq_key('v', &drm_client_sysrq_restore_op); + + list_add(&dev->client_sysrq_list, &drm_client_sysrq_dev_list); +} + +void drm_client_sysrq_unregister(struct drm_device *dev) +{ + guard(mutex)(&drm_client_sysrq_dev_lock); + + /* remove device from global restore list */ + if (!drm_WARN_ON(dev, list_empty(&dev->client_sysrq_list))) + list_del(&dev->client_sysrq_list); + + /* no devices left; unregister key */ + if (list_empty(&drm_client_sysrq_dev_list)) + unregister_sysrq_key('v', &drm_client_sysrq_restore_op); +} +#endif diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 8e3cb08241c8..2915118436ce 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -733,6 +733,7 @@ static int drm_dev_init(struct drm_device *dev, INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->filelist_internal); INIT_LIST_HEAD(&dev->clientlist); + INIT_LIST_HEAD(&dev->client_sysrq_list); INIT_LIST_HEAD(&dev->vblank_event_list); =20 spin_lock_init(&dev->event_lock); @@ -1100,6 +1101,7 @@ int drm_dev_register(struct drm_device *dev, unsigned= long flags) goto err_unload; } drm_panic_register(dev); + drm_client_sysrq_register(dev); =20 DRM_INFO("Initialized %s %d.%d.%d for %s on minor %d\n", driver->name, driver->major, driver->minor, @@ -1144,6 +1146,7 @@ void drm_dev_unregister(struct drm_device *dev) { dev->registered =3D false; =20 + drm_client_sysrq_unregister(dev); drm_panic_unregister(dev); =20 drm_client_dev_unregister(dev); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helpe= r.c index 1392738ce2fe..9a734017756b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -32,7 +32,6 @@ #include #include #include -#include #include =20 #include @@ -270,42 +269,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct d= rm_fb_helper *fb_helper, b } EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); =20 -#ifdef CONFIG_MAGIC_SYSRQ -/* emergency restore, don't bother with error reporting */ -static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) -{ - struct drm_fb_helper *helper; - - mutex_lock(&kernel_fb_helper_lock); - list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { - struct drm_device *dev =3D helper->dev; - - if (dev->switch_power_state =3D=3D DRM_SWITCH_POWER_OFF) - continue; - - mutex_lock(&helper->lock); - drm_client_modeset_commit_locked(&helper->client); - mutex_unlock(&helper->lock); - } - mutex_unlock(&kernel_fb_helper_lock); -} - -static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work= _fn); - -static void drm_fb_helper_sysrq(u8 dummy1) -{ - schedule_work(&drm_fb_helper_restore_work); -} - -static const struct sysrq_key_op sysrq_drm_fb_helper_restore_op =3D { - .handler =3D drm_fb_helper_sysrq, - .help_msg =3D "force-fb(v)", - .action_msg =3D "Restore framebuffer console", -}; -#else -static const struct sysrq_key_op sysrq_drm_fb_helper_restore_op =3D { }; -#endif - static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) { struct drm_fb_helper *fb_helper =3D info->par; @@ -602,11 +565,8 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helpe= r) drm_fb_helper_release_info(fb_helper); =20 mutex_lock(&kernel_fb_helper_lock); - if (!list_empty(&fb_helper->kernel_fb_list)) { + if (!list_empty(&fb_helper->kernel_fb_list)) list_del(&fb_helper->kernel_fb_list); - if (list_empty(&kernel_fb_helper_list)) - unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); - } mutex_unlock(&kernel_fb_helper_lock); =20 if (!fb_helper->client.funcs) @@ -1840,9 +1800,6 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_= fb_helper *fb_helper) info->node, info->fix.id); =20 mutex_lock(&kernel_fb_helper_lock); - if (list_empty(&kernel_fb_helper_list)) - register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); - list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); mutex_unlock(&kernel_fb_helper_lock); =20 diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 5a3bed48ab1f..59cbac12a6d6 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -56,6 +56,17 @@ static inline void drm_client_debugfs_init(struct drm_de= vice *dev) { } #endif =20 +/* drm_client_sysrq.c */ +#if defined(CONFIG_DRM_CLIENT) && defined(CONFIG_MAGIC_SYSRQ) +void drm_client_sysrq_register(struct drm_device *dev); +void drm_client_sysrq_unregister(struct drm_device *dev); +#else +void drm_client_sysrq_register(struct drm_device *dev) +{ } +void drm_client_sysrq_unregister(struct drm_device *dev) +{ } +#endif + /* drm_file.c */ extern struct mutex drm_global_mutex; bool drm_dev_needs_global_mutex(struct drm_device *dev); diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index 778b2cca6c49..5af49c5c3778 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -238,6 +238,14 @@ struct drm_device { */ struct list_head clientlist; =20 + /** + * @client_sysrq_list: + * + * Entry into list of devices registered for sysrq. Allows in-kernel + * clients on this device to handle sysrq keys. + */ + struct list_head client_sysrq_list; + /** * @vblank_disable_immediate: * --=20 2.51.1