Re: [PATCH v15 4/6] reboot: extend psc_reason with power-on and reset causes
From: Matti Vaittinen
Date: Thu Sep 24 2026 - 08:23:59 EST
On 24/09/2026 10:08, Faruque Ansari wrote:
psc_reason covered only the protection reasons. Extend it to mirror the
full POWER_ON_REASON_* vocabulary - power-on, watchdog, software,
external, RTC, reset button, CPU clock and crystal failures - so a
provider can report why the system last powered on, not only why it was
shut down. New values are appended to keep the existing numeric ABI.
Co-developed-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
Signed-off-by: Faruque Ansari <faruque.ansari@xxxxxxxxxxxxxxxx>
Reviewed-by: Matti Vaittinen <mazziesaccount@xxxxxxxxx>
changes v15:
- add a static_assert() tying ARRAY_SIZE(psc_reason_descs) to
PSCR_REASON_COUNT, so a future enum addition without a matching
table entry fails the build instead of silently reading a hole
(Matti Vaittinen)
- Add Reviewed-by tags from Matti Vaittinen.
changes v12:
- new patch
---
include/linux/reboot.h | 28 ++++++++++++++++++++++++++++
kernel/reboot.c | 12 ++++++++++++
2 files changed, 40 insertions(+)
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 4c5327dd7645..13f004ad1066 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -225,9 +225,28 @@ extern void orderly_reboot(void);
* management errors, or an unrecoverable hardware fault requiring
* immediate response.
*
+ * @PSCR_POWER_ON: Regular cold power-on (e.g. via a PMIC power-on request).
+ *
+ * @PSCR_WATCHDOG: Reset caused by a watchdog timeout.
+ *
+ * @PSCR_SOFTWARE: Software-initiated reset or reboot.
+ *
+ * @PSCR_EXTERNAL: Reset asserted through an external pin or reset input.
+ *
+ * @PSCR_RTC: Wake-up or power-on triggered by the RTC.
+ *
+ * @PSCR_RESET_BUTTON: Reset triggered by a user reset button.
+ *
+ * @PSCR_CPU_CLK_FAIL: Reset caused by a CPU clock failure.
+ *
+ * @PSCR_XTAL_FAIL: Reset caused by a crystal oscillator failure.
+ *
* @PSCR_REASON_COUNT: Number of defined power state change reasons. This
* value is useful for range checking and potential future extensions
* while maintaining compatibility.
+ *
+ * The reasons mirror the POWER_ON_REASON_* strings in
+ * <linux/power/power_on_reason.h>; keep the two in sync when extending.
*/
enum psc_reason {
PSCR_UNKNOWN,
@@ -236,6 +255,15 @@ enum psc_reason {
PSCR_REGULATOR_FAILURE,
PSCR_OVER_TEMPERATURE,
PSCR_EC_PANIC,
+ /* Append new reasons here; the numeric order is ABI. */
+ PSCR_POWER_ON,
+ PSCR_WATCHDOG,
+ PSCR_SOFTWARE,
+ PSCR_EXTERNAL,
+ PSCR_RTC,
+ PSCR_RESET_BUTTON,
+ PSCR_CPU_CLK_FAIL,
+ PSCR_XTAL_FAIL,
/* Number of reasons */
PSCR_REASON_COUNT,
diff --git a/kernel/reboot.c b/kernel/reboot.c
index e53fb31bad06..7094c7a8f315 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -7,7 +7,9 @@
#define pr_fmt(fmt) "reboot: " fmt
+#include <linux/array_size.h>
#include <linux/atomic.h>
+#include <linux/build_bug.h>
#include <linux/ctype.h>
#include <linux/export.h>
#include <linux/kexec.h>
@@ -1102,7 +1104,17 @@ static const struct psc_reason_desc psc_reason_descs[] = {
[PSCR_REGULATOR_FAILURE] = { "regulator-failure", POWER_ON_REASON_REGULATOR_FAILURE },
[PSCR_OVER_TEMPERATURE] = { "over-temperature", POWER_ON_REASON_OVER_TEMPERATURE },
[PSCR_EC_PANIC] = { "ec-panic", POWER_ON_REASON_EC_PANIC },
+ [PSCR_POWER_ON] = { "power-on", POWER_ON_REASON_REGULAR },
+ [PSCR_WATCHDOG] = { "watchdog", POWER_ON_REASON_WATCHDOG },
+ [PSCR_SOFTWARE] = { "software", POWER_ON_REASON_SOFTWARE },
+ [PSCR_EXTERNAL] = { "external", POWER_ON_REASON_EXTERNAL },
+ [PSCR_RTC] = { "rtc", POWER_ON_REASON_RTC },
+ [PSCR_RESET_BUTTON] = { "reset-button", POWER_ON_REASON_RST_BTN },
+ [PSCR_CPU_CLK_FAIL] = { "cpu-clock-failure", POWER_ON_REASON_CPU_CLK_FAIL },
+ [PSCR_XTAL_FAIL] = { "crystal-failure", POWER_ON_REASON_XTAL_FAIL },
};
+static_assert(ARRAY_SIZE(psc_reason_descs) == PSCR_REASON_COUNT,
+ "psc_reason_descs[] must have an entry for every psc_reason");
Thanks Faruque. This is better than nothing, but if I read it right, it won't still catch missing initializations when last item is initialized (but not all items). Eg:
enum {
PSCR_REGULATOR_FAILURE,
PSCR_OVER_TEMPERATURE,
PSCR_EC_PANIC,
...
PSCR_REASON_COUNT
};
static const struct psc_reason_desc psc_reason_descs[] = {
[ PSCR_REASON_COUNT - 1] = { "foo", BAR }
};
static_assert(ARRAY_SIZE(psc_reason_descs) == PSCR_REASON_COUNT,
"psc_reason_descs[] must have an entry for every psc_reason");
would pass the check, but accessors would crash to uninitialized entries. Hence, I would still prefer the run-time NULL checks.
Oh, and I just noticed there is comma following the 'PSCR_REASON_COUNT' in the enum. Since 'PSCR_REASON_COUNT' should always be kept as the last enum value, the comma should be omitted.
Other than this - I like the changes you implemented this series. Won't reply to other patches, but I think this is a very nice series!
Yours,
-- Matti
--
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland
~~ When things go utterly wrong vim users can always type :help! ~~