diff mbox series

[1/4] PM: Add sysfs file for energy consumed over sleep cycle

Message ID 20250208162210.3929473-2-superm1@kernel.org
State New
Headers show
Series Improvements to ACPI battery handling over s2idle | expand

Commit Message

Mario Limonciello Feb. 8, 2025, 4:22 p.m. UTC
From: Mario Limonciello <mario.limonciello@amd.com>

During a sleep cycle the system will consume power to keep the
platform in s2idle or s3. On systems running on a battery this
can be measured by comparing battery before and after the sleep
cycle.

Add a symbol for the battery to report current energy level and
a sysfs file to show this information to a user.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 Documentation/ABI/testing/sysfs-power |  8 ++++++++
 include/linux/suspend.h               |  2 ++
 kernel/power/main.c                   | 10 ++++++++++
 3 files changed, 20 insertions(+)
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index a3942b1036e25..e263355f99fc1 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -442,6 +442,14 @@  Description:
 		'total_hw_sleep' and 'last_hw_sleep' may not be accurate.
 		This number is measured in microseconds.
 
+What:		/sys/power/suspend_stats/last_sleep_energy
+Date:		March 2025
+Contact:	Mario Limonciello <mario.limonciello@amd.com>
+Description:
+		The /sys/power/suspend_stats/last_sleep_energy file
+		contains the amount of energy that the battery consumed
+		during the last sleep cycle. This number is measured in mAh.
+
 What:		/sys/power/sync_on_suspend
 Date:		October 2019
 Contact:	Jonas Meurer <jonas@freesources.org>
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index da6ebca3ff774..9627e2394c8a9 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -441,6 +441,7 @@  extern int unregister_pm_notifier(struct notifier_block *nb);
 extern void ksys_sync_helper(void);
 extern void pm_report_hw_sleep_time(u64 t);
 extern void pm_report_max_hw_sleep(u64 t);
+extern void pm_report_sleep_energy(u64 t);
 
 #define pm_notifier(fn, pri) {				\
 	static struct notifier_block fn##_nb =			\
@@ -484,6 +485,7 @@  static inline int unregister_pm_notifier(struct notifier_block *nb)
 
 static inline void pm_report_hw_sleep_time(u64 t) {};
 static inline void pm_report_max_hw_sleep(u64 t) {};
+static inline void pm_report_sleep_energy(u64 t) {};
 
 static inline void ksys_sync_helper(void) {}
 
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 6254814d48171..9305c86e0b91a 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -321,6 +321,7 @@  struct suspend_stats {
 	u64 last_hw_sleep;
 	u64 total_hw_sleep;
 	u64 max_hw_sleep;
+	u64 last_sleep_energy;
 	enum suspend_stat_step failed_steps[REC_FAILED_NUM];
 };
 
@@ -368,6 +369,12 @@  void pm_report_hw_sleep_time(u64 t)
 }
 EXPORT_SYMBOL_GPL(pm_report_hw_sleep_time);
 
+void pm_report_sleep_energy(u64 t)
+{
+	suspend_stats.last_sleep_energy = t;
+}
+EXPORT_SYMBOL_GPL(pm_report_sleep_energy);
+
 void pm_report_max_hw_sleep(u64 t)
 {
 	suspend_stats.max_hw_sleep = t;
@@ -399,6 +406,7 @@  suspend_attr(fail, "%u\n");
 suspend_attr(last_hw_sleep, "%llu\n");
 suspend_attr(total_hw_sleep, "%llu\n");
 suspend_attr(max_hw_sleep, "%llu\n");
+suspend_attr(last_sleep_energy, "%llu\n");
 
 #define suspend_step_attr(_name, step)		\
 static ssize_t _name##_show(struct kobject *kobj,		\
@@ -477,6 +485,7 @@  static struct attribute *suspend_attrs[] = {
 	&last_hw_sleep.attr,
 	&total_hw_sleep.attr,
 	&max_hw_sleep.attr,
+	&last_sleep_energy.attr,
 	NULL,
 };
 
@@ -484,6 +493,7 @@  static umode_t suspend_attr_is_visible(struct kobject *kobj, struct attribute *a
 {
 	if (attr != &last_hw_sleep.attr &&
 	    attr != &total_hw_sleep.attr &&
+	    attr != &last_sleep_energy.attr &&
 	    attr != &max_hw_sleep.attr)
 		return 0444;