From 31ad034f3ee879d0fddd75bdf27e6e7127ff9d2e Mon Sep 17 00:00:00 2001 From: Ping Xiao Date: Fri, 12 Aug 2022 20:22:55 +0800 Subject: [PATCH] Power: Add /proc/wakeup_sources for Battery Tracer Because /sys/kernel/debug will not be mounted on user build release, it's hard to debug power issues due to the lack of wakeup_sources system file node which is used by Battery Tracer. Add /proc/wakeup_sources for Battery Tracer to use Change-Id: I5b6774a25cda4d6344fbe266e8effb53f478edd7 Reviewed-on: https://gerrit.mot.com/2361839 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Jianqi Yang Submit-Approved: Jira Key --- drivers/power/wakeup_sources/Android.mk | 9 ++ drivers/power/wakeup_sources/Kbuild | 6 + drivers/power/wakeup_sources/Makefile | 14 ++ drivers/power/wakeup_sources/wakeup_sources.c | 144 ++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 drivers/power/wakeup_sources/Android.mk create mode 100644 drivers/power/wakeup_sources/Kbuild create mode 100644 drivers/power/wakeup_sources/Makefile create mode 100644 drivers/power/wakeup_sources/wakeup_sources.c diff --git a/drivers/power/wakeup_sources/Android.mk b/drivers/power/wakeup_sources/Android.mk new file mode 100644 index 000000000000..97a0a6aebbed --- /dev/null +++ b/drivers/power/wakeup_sources/Android.mk @@ -0,0 +1,9 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := wakeup_sources.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +KBUILD_OPTIONS_GKI += GKI_OBJ_MODULE_DIR=gki +include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/power/wakeup_sources/Kbuild b/drivers/power/wakeup_sources/Kbuild new file mode 100644 index 000000000000..95618af7359e --- /dev/null +++ b/drivers/power/wakeup_sources/Kbuild @@ -0,0 +1,6 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include + +obj-m += wakeup_sources.o + diff --git a/drivers/power/wakeup_sources/Makefile b/drivers/power/wakeup_sources/Makefile new file mode 100644 index 000000000000..bfbdc14740ef --- /dev/null +++ b/drivers/power/wakeup_sources/Makefile @@ -0,0 +1,14 @@ +all: modules + +modules: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install + +%: + $(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS) + +clean: + rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers + rm -rf .tmp_versions diff --git a/drivers/power/wakeup_sources/wakeup_sources.c b/drivers/power/wakeup_sources/wakeup_sources.c new file mode 100644 index 000000000000..237c67764e78 --- /dev/null +++ b/drivers/power/wakeup_sources/wakeup_sources.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * /proc/wakeup_sources + */ + +struct proc_dir_entry *g_proc_wakeup_sources; +int g_lock_wakeup_sources; + +/** + * print_wakeup_source_stats - Print wakeup source statistics information. + * @m: seq_file to print the statistics into. + * @ws: Wakeup source object to print the statistics for. + */ +static int print_wakeup_source_stats(struct seq_file *m, + struct wakeup_source *ws) +{ + unsigned long flags; + ktime_t total_time; + ktime_t max_time; + unsigned long active_count; + ktime_t active_time; + ktime_t prevent_sleep_time; + + spin_lock_irqsave(&ws->lock, flags); + + total_time = ws->total_time; + max_time = ws->max_time; + prevent_sleep_time = ws->prevent_sleep_time; + active_count = ws->active_count; + if (ws->active) { + ktime_t now = ktime_get(); + + active_time = ktime_sub(now, ws->last_time); + total_time = ktime_add(total_time, active_time); + if (active_time > max_time) + max_time = active_time; + + if (ws->autosleep_enabled) + prevent_sleep_time = ktime_add(prevent_sleep_time, + ktime_sub(now, ws->start_prevent_time)); + } else { + active_time = 0; + } + + seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n", + ws->name, active_count, ws->event_count, + ws->wakeup_count, ws->expire_count, + ktime_to_ms(active_time), ktime_to_ms(total_time), + ktime_to_ms(max_time), ktime_to_ms(ws->last_time), + ktime_to_ms(prevent_sleep_time)); + + spin_unlock_irqrestore(&ws->lock, flags); + + return 0; +} + +static void *wakeup_sources_stats_seq_start(struct seq_file *m, + loff_t *pos) +{ + struct wakeup_source *ws; + loff_t n = *pos; + + if (n == 0) { + seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" + "expire_count\tactive_since\ttotal_time\tmax_time\t" + "last_change\tprevent_suspend_time\n"); + } + + g_lock_wakeup_sources = wakeup_sources_read_lock(); + for_each_wakeup_source(ws) { + if (n-- <= 0) + return ws; + } + + return NULL; +} + +static void *wakeup_sources_stats_seq_next(struct seq_file *m, + void *v, loff_t *pos) +{ + struct wakeup_source *ws = v; + struct wakeup_source *next_ws = NULL; + + ++(*pos); + next_ws = wakeup_sources_walk_next(ws); + + return next_ws; +} + +static void wakeup_sources_stats_seq_stop(struct seq_file *m, void *v) +{ + wakeup_sources_read_unlock(g_lock_wakeup_sources); +} + +/** + * wakeup_sources_stats_seq_show - Print wakeup sources statistics information. + * @m: seq_file to print the statistics into. + * @v: wakeup_source of each iteration + */ +static int wakeup_sources_stats_seq_show(struct seq_file *m, void *v) +{ + struct wakeup_source *ws = v; + + print_wakeup_source_stats(m, ws); + + return 0; +} + +static const struct seq_operations wakeup_sources_stats_seq_ops = { + .start = wakeup_sources_stats_seq_start, + .next = wakeup_sources_stats_seq_next, + .stop = wakeup_sources_stats_seq_stop, + .show = wakeup_sources_stats_seq_show, +}; + +static int __init proc_wakeup_sources_init(void) +{ + pr_debug("%s(), %d\n", __func__, __LINE__); + g_proc_wakeup_sources = proc_create_seq("wakeup_sources", + S_IRUGO, NULL, &wakeup_sources_stats_seq_ops); + return 0; +} + +static void __exit proc_wakeup_sources_exit(void) +{ + pr_debug("%s(), %d\n", __func__, __LINE__); + proc_remove(g_proc_wakeup_sources); +} + +module_init(proc_wakeup_sources_init); +module_exit(proc_wakeup_sources_exit); + +MODULE_LICENSE("GPL");