<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body><p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;"><span style="font-size:0.75em;">On Thursday, March 28, 2024 8:03:43 AM EDT Jocelyn Falempe wrote:</span></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> From: Daniel Vetter <daniel.vetter@ffwll.ch></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Rough sketch for the locking of drm panic printing code. The upshot of</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> this approach is that we can pretty much entirely rely on the atomic</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> commit flow, with the pair of raw_spin_lock/unlock providing any</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> barriers we need, without having to create really big critical</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> sections in code.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> This also avoids the need that drivers must explicitly update the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> panic handler state, which they might forget to do, or not do</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> consistently, and then we blow up in the worst possible times.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> It is somewhat racy against a concurrent atomic update, and we might</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> write into a buffer which the hardware will never display. But there's</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> fundamentally no way to avoid that - if we do the panic state update</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> explicitly after writing to the hardware, we might instead write to an</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> old buffer that the user will barely ever see.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Note that an rcu protected deference of plane->state would give us the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> the same guarantees, but it has the downside that we then need to</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> protect the plane state freeing functions with call_rcu too. Which</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> would very widely impact a lot of code and therefore doesn't seem</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> worth the complexity compared to a raw spinlock with very tiny</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> critical sections. Plus rcu cannot be used to protect access to</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> peek/poke registers anyway, so we'd still need it for those cases.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Peek/poke registers for vram access (or a gart pte reserved just for</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> panic code) are also the reason I've gone with a per-device and not</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> per-plane spinlock, since usually these things are global for the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> entire display. Going with per-plane locks would mean drivers for such</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> hardware would need additional locks, which we don't want, since it</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> deviates from the per-console takeoverlocks design.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Longer term it might be useful if the panic notifiers grow a bit more</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> structure than just the absolute bare</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> EXPORT_SYMBOL(panic_notifier_list) - somewhat aside, why is that not</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> EXPORT_SYMBOL_GPL ... If panic notifiers would be more like console</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> drivers with proper register/unregister interfaces we could perhaps</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> reuse the very fancy console lock with all it's check and takeover</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> semantics that John Ogness is developing to fix the console_lock mess.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> But for the initial cut of a drm panic printing support I don't think</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> we need that, because the critical sections are extremely small and</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> only happen once per display refresh. So generally just 60 tiny locked</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> sections per second, which is nothing compared to a serial console</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> running a 115kbaud doing really slow mmio writes for each byte. So for</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> now the raw spintrylock in drm panic notifier callback should be good</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> enough.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Another benefit of making panic notifiers more like full blown</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> consoles (that are used in panics only) would be that we get the two</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> stage design, where first all the safe outputs are used. And then the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> dangerous takeover tricks are deployed (where for display drivers we</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> also might try to intercept any in-flight display buffer flips, which</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> if we race and misprogram fifos and watermarks can hang the memory</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> controller on some hw).</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> For context the actual implementation on the drm side is by Jocelyn</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> and this patch is meant to be combined with the overall approach in</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> v7 (v8 is a bit less flexible, which I think is the wrong direction):</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> https://lore.kernel.org/dri-devel/20240104160301.185915-1-jfalempe@redhat.com/</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Note that the locking is very much not correct there, hence this</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> separate rfc.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> v2:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> - fix authorship, this was all my typing</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> - some typo oopsies</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> - link to the drm panic work by Jocelyn for context</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> v10:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> - Use spinlock_irqsave/restore (John Ogness)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> v11:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> - Use macro instead of inline functions for drm_panic_lock/unlock (John Ogness)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Jocelyn Falempe <jfalempe@redhat.com></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Andrew Morton <akpm@linux-foundation.org></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Lukas Wunner <lukas@wunner.de></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Petr Mladek <pmladek@suse.com></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Steven Rostedt <rostedt@goodmis.org></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: John Ogness <john.ogness@linutronix.de></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Sergey Senozhatsky <senozhatsky@chromium.org></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Maxime Ripard <mripard@kernel.org></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Thomas Zimmermann <tzimmermann@suse.de></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: David Airlie <airlied@gmail.com></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Cc: Daniel Vetter <daniel@ffwll.ch></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> ---</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> drivers/gpu/drm/drm_atomic_helper.c | 4 ++</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> drivers/gpu/drm/drm_drv.c | 1 +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> include/drm/drm_mode_config.h | 10 +++</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> include/drm/drm_panic.h | 100 ++++++++++++++++++++++++++++</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> 4 files changed, 115 insertions(+)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> create mode 100644 include/drm/drm_panic.h</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> index 39ef0a6addeb..fb97b51b38f1 100644</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> --- a/drivers/gpu/drm/drm_atomic_helper.c</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +++ b/drivers/gpu/drm/drm_atomic_helper.c</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -38,6 +38,7 @@</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> #include <drm/drm_drv.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> #include <drm/drm_framebuffer.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> #include <drm/drm_gem_atomic_helper.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#include <drm/drm_panic.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> #include <drm/drm_print.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> #include <drm/drm_self_refresh_helper.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> #include <drm/drm_vblank.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -3016,6 +3017,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> bool stall)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> {</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> int i, ret;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + unsigned long flags;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> struct drm_connector *connector;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> struct drm_connector_state *old_conn_state, *new_conn_state;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> struct drm_crtc *crtc;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -3099,6 +3101,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> }</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> }</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + drm_panic_lock(state->dev, flags);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> WARN_ON(plane->state != old_plane_state);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -3108,6 +3111,7 @@ int drm_atomic_helper_swap_state(struct drm_atomic_state *state,</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> state->planes[i].state = old_plane_state;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> plane->state = new_plane_state;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> }</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + drm_panic_unlock(state->dev, flags);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> WARN_ON(obj->state != old_obj_state);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> index 243cacb3575c..c157500b3135 100644</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> --- a/drivers/gpu/drm/drm_drv.c</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +++ b/drivers/gpu/drm/drm_drv.c</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -638,6 +638,7 @@ static int drm_dev_init(struct drm_device *dev,</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> mutex_init(&dev->filelist_mutex);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> mutex_init(&dev->clientlist_mutex);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> mutex_init(&dev->master_mutex);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + raw_spin_lock_init(&dev->mode_config.panic_lock);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> ret = drmm_add_action_or_reset(dev, drm_dev_init_release, NULL);</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> if (ret)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> index 973119a9176b..e79f1a557a22 100644</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> --- a/include/drm/drm_mode_config.h</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +++ b/include/drm/drm_mode_config.h</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -505,6 +505,16 @@ struct drm_mode_config {</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> struct list_head plane_list;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + /**</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @panic_lock:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Raw spinlock used to protect critical sections of code that access</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * the display hardware or modeset software state, which the panic</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * printing code must be protected against. See drm_panic_trylock(),</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_panic_lock() and drm_panic_unlock().</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + struct raw_spinlock panic_lock;</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> /**</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> * @num_crtc:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> new file mode 100644</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> index 000000000000..68f57710d2d1</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> --- /dev/null</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +++ b/include/drm/drm_panic.h</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> @@ -0,0 +1,100 @@</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +/* SPDX-License-Identifier: GPL-2.0 or MIT */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#ifndef __DRM_PANIC_H__</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#define __DRM_PANIC_H__</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#include <drm/drm_device.h></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +/*</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Copyright (c) 2024 Intel</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +/**</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_panic_trylock - try to enter the panic printing critical section</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @dev: struct drm_device</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @flags: unsigned long irq flags you need to pass to the unlock() counterpart</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * This function must be called by any panic printing code. The panic printing</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * attempt must be aborted if the trylock fails.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Panic printing code can make the following assumptions while holding the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * panic lock:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Anything protected by drm_panic_lock() and drm_panic_unlock() pairs is safe</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * to access.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Furthermore the panic printing code only registers in drm_dev_unregister()</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * and gets removed in drm_dev_unregister(). This allows the panic code to</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * safely access any state which is invariant in between these two function</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * calls, like the list of planes drm_mode_config.plane_list or most of the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * struct drm_plane structure.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Specifically thanks to the protection around plane updates in</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_atomic_helper_swap_state() the following additional guarantees hold:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - It is safe to deference the drm_plane.state pointer.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Anything in struct drm_plane_state or the driver's subclass thereof which</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * stays invariant after the atomic check code has finished is safe to access.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Specifically this includes the reference counted pointers to framebuffer</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * and buffer objects.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Anything set up by drm_plane_helper_funcs.fb_prepare and cleaned up</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_plane_helper_funcs.fb_cleanup is safe to access, as long as it stays</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * invariant between these two calls. This also means that for drivers using</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * dynamic buffer management the framebuffer is pinned, and therefer all</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * relevant datastructures can be accessed without taking any further locks</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * (which would be impossible in panic context anyway).</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Importantly, software and hardware state set up by</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_plane_helper_funcs.begin_fb_access and</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_plane_helper_funcs.end_fb_access is not safe to access.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Drivers must not make any assumptions about the actual state of the hardware,</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * unless they explicitly protected these hardware access with drm_panic_lock()</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * and drm_panic_unlock().</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Returns:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * 0 when failing to acquire the raw spinlock, nonzero on success.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#define drm_panic_trylock(dev, flags) \</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + raw_spin_trylock_irqsave(&dev->mode_config.panic_lock, flags)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +/**</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_panic_lock - protect panic printing relevant state</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @dev: struct drm_device</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @flags: unsigned long irq flags you need to pass to the unlock() counterpart</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * This function must be called to protect software and hardware state that the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * panic printing code must be able to rely on. The protected sections must be</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * as small as possible. It uses the irqsave/irqrestore variant, and can be</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * called from irq handler. Examples include:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Access to peek/poke or other similar registers, if that is the way the</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * driver prints the pixels into the scanout buffer at panic time.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - Updates to pointers like drm_plane.state, allowing the panic handler to</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * safely deference these. This is done in drm_atomic_helper_swap_state().</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * - An state that isn't invariant and that the driver must be able to access</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * during panic printing.</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Returns:</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * The irqflags needed to call drm_panic_unlock().</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#define drm_panic_lock(dev, flags) \</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + raw_spin_lock_irqsave(&dev->mode_config.panic_lock, flags)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +/**</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_panic_unlock - end of the panic printing critical section</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @dev: struct drm_device</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * @flags: irq flags that were returned when acquiring the lock</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + *</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * Unlocks the raw spinlock acquired by either drm_panic_lock() or</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + * drm_panic_trylock().</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#define drm_panic_unlock(dev, flags) \</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> + raw_spin_unlock_irqrestore(&dev->mode_config.panic_lock, flags)</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> +#endif /* __DRM_PANIC_H__ */</p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;"><br /></p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">I can't offer much feedback, except that I have tested this in QEMU with SimpleDRM and it works great</p>
<p style="margin-top:12;margin-bottom:12;margin-left:0;margin-right:0;"> </p>
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">Thanks!</p>
</body>
</html>