[PATCH 1/2] power: reset: pscrr: add kernel panic reason tracking
From: Faruque Ansari
Date: Tue Jul 14 2026 - 05:55:38 EST
Without this change, a kernel panic leaves no trace in NVMEM — the
system resets silently and the next boot sees PSCR_UNKNOWN, making
post-mortem diagnosis harder.
Add a panic notifier so the recorded shutdown reason survives a kernel
panic and is available for inspection on the next boot. Also introduce
PSCR_KERNEL_PANIC as a dedicated reason code with its human-readable
string so userspace and bootloaders can distinguish a panic-driven reset
from other reset causes.
Signed-off-by: Faruque Ansari <faruque.ansari@xxxxxxxxxxxxxxxx>
---
drivers/power/reset/pscrr.c | 32 ++++++++++++++++++++++++++++++++
include/linux/power/power_on_reason.h | 1 +
include/linux/reboot.h | 1 +
kernel/reboot.c | 1 +
4 files changed, 35 insertions(+)
diff --git a/drivers/power/reset/pscrr.c b/drivers/power/reset/pscrr.c
index 92e8ef97421c..b5906f127e88 100644
--- a/drivers/power/reset/pscrr.c
+++ b/drivers/power/reset/pscrr.c
@@ -60,6 +60,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include <linux/power/power_on_reason.h>
#include <linux/pscrr.h>
#include <linux/reboot.h>
@@ -78,6 +79,7 @@ struct pscrr_core {
/* Kobject for sysfs */
struct kobject *kobj;
struct notifier_block reboot_nb;
+ struct notifier_block panic_nb;
};
static struct pscrr_core g_pscrr = {
@@ -136,6 +138,30 @@ static int pscrr_reboot_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
+static int pscrr_panic_notifier(struct notifier_block *nb,
+ unsigned long action, void *unused)
+{
+ int ret;
+ struct pscrr_backend *backend;
+
+ backend = g_pscrr.backend;
+
+ if (!backend || !backend->ops || !backend->ops->write_reason)
+ return NOTIFY_OK;
+
+ set_psc_reason(PSCR_KERNEL_PANIC);
+ ret = backend->ops->write_reason(get_psc_reason());
+ if (ret)
+ pr_err("PSCRR: Failed to store reason %d (%s) at panic, err=%pe\n",
+ get_psc_reason(), psc_reason_to_str(get_psc_reason()),
+ ERR_PTR(ret));
+ else
+ pr_debug("PSCRR: Stored reason %d (%s) at panic.\n",
+ get_psc_reason(), psc_reason_to_str(get_psc_reason()));
+
+ return NOTIFY_OK;
+}
+
/*----------------------------------------------------------------------*/
/* Sysfs Interface */
/*----------------------------------------------------------------------*/
@@ -349,6 +375,10 @@ int pscrr_core_init(const struct pscrr_backend_ops *ops)
goto err_free;
}
+ /* Setup the panic notifier to persist reason on kernel panic */
+ g_pscrr.panic_nb.notifier_call = pscrr_panic_notifier;
+ atomic_notifier_chain_register(&panic_notifier_list, &g_pscrr.panic_nb);
+
/* Create a kobject and sysfs group under /sys/kernel/pscrr */
g_pscrr.kobj = kobject_create_and_add("pscrr", kernel_kobj);
if (!g_pscrr.kobj) {
@@ -371,6 +401,7 @@ int pscrr_core_init(const struct pscrr_backend_ops *ops)
err_kobj_put:
kobject_put(g_pscrr.kobj);
err_unreg_reboot:
+ atomic_notifier_chain_unregister(&panic_notifier_list, &g_pscrr.panic_nb);
unregister_reboot_notifier(&g_pscrr.reboot_nb);
err_free:
kfree(g_pscrr.backend);
@@ -391,6 +422,7 @@ void pscrr_core_exit(void)
kobject_put(g_pscrr.kobj);
}
+ atomic_notifier_chain_unregister(&panic_notifier_list, &g_pscrr.panic_nb);
unregister_reboot_notifier(&g_pscrr.reboot_nb);
kfree(g_pscrr.backend);
diff --git a/include/linux/power/power_on_reason.h b/include/linux/power/power_on_reason.h
index bf9501792696..4ac1bdfdc211 100644
--- a/include/linux/power/power_on_reason.h
+++ b/include/linux/power/power_on_reason.h
@@ -19,5 +19,6 @@
#define POWER_ON_REASON_REGULATOR_FAILURE "regulator failure"
#define POWER_ON_REASON_OVER_TEMPERATURE "over temperature"
#define POWER_ON_REASON_EC_PANIC "EC panic"
+#define POWER_ON_REASON_KERNEL_PANIC "kernel panic"
#endif /* POWER_ON_REASON_H */
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 6477910c6a9e..a492b1652038 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -236,6 +236,7 @@ enum psc_reason {
PSCR_REGULATOR_FAILURE,
PSCR_OVER_TEMPERATURE,
PSCR_EC_PANIC,
+ PSCR_KERNEL_PANIC,
/* Number of reasons */
PSCR_REASON_COUNT,
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 61e0027b7550..f1df52f8773a 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -1065,6 +1065,7 @@ static const char * const pscr_reason_strs[] = {
[PSCR_REGULATOR_FAILURE] = POWER_ON_REASON_REGULATOR_FAILURE,
[PSCR_OVER_TEMPERATURE] = POWER_ON_REASON_OVER_TEMPERATURE,
[PSCR_EC_PANIC] = POWER_ON_REASON_EC_PANIC,
+ [PSCR_KERNEL_PANIC] = POWER_ON_REASON_KERNEL_PANIC,
};
/**
--
2.34.1