[PATCH v2 1/3] power: reset: pscrr: add kernel panic reason tracking

Faruque Ansari <[email protected]> Wed, 22 Jul 2026 20:43:00 +0530
Newsgroups org.kernel.vger.linux-watchdog,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm
Message-ID <[email protected]>
Kernel panic resets are not recorded in NVMEM, causing subsequent
boots to report PSCR_UNKNOWN and making post-mortem analysis more
difficult.

Register a panic notifier to preserve the shutdown reason across
panic-triggered resets. Add PSCR_KERNEL_PANIC as a dedicated reset
reason code and its corresponding reason string to identify kernel
panic resets on subsequent boots.

Signed-off-by: Faruque Ansari <[email protected]>
---
 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