Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 4f1ea1a6 authored by derfelot's avatar derfelot
Browse files

power: Add log for device wakeups and wakeup interrupts from Sony kernel

Taken from Sony 47.2.A.10.107 stock kernel
parent 927b73ac
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@
 * domain dependencies may differ from the ancestral dependencies that the
 * subsystem list maintains.
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#include <linux/device.h>
#include <linux/kallsyms.h>
@@ -34,6 +39,10 @@
#include <linux/cpuidle.h>
#include <linux/timer.h>
#include <linux/wakeup_reason.h>
#ifdef CONFIG_PM_WAKEUP_TIMES
#include <linux/math64.h>
#include <linux/wait.h>
#endif

#include "../base.h"
#include "power.h"
@@ -57,6 +66,11 @@ static LIST_HEAD(dpm_late_early_list);
static LIST_HEAD(dpm_noirq_list);

struct suspend_stats suspend_stats;
#ifdef CONFIG_PM_WAKEUP_TIMES
struct suspend_stats_queue suspend_stats_queue;
static ktime_t suspend_start_time;
static ktime_t resume_start_time;
#endif
static DEFINE_MUTEX(dpm_list_mtx);
static pm_message_t pm_transition;

@@ -376,6 +390,100 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
		usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
}

#ifdef CONFIG_PM_WAKEUP_TIMES
void dpm_log_start_time(pm_message_t state)
{
	switch (state.event) {
	case PM_EVENT_RESUME:
		resume_start_time = ktime_get_boottime();
		break;
	case PM_EVENT_SUSPEND:
		suspend_start_time = ktime_get_boottime();
		break;
	default:
		break;
	}
}
EXPORT_SYMBOL_GPL(dpm_log_start_time);

void dpm_log_wakeup_stats(pm_message_t state)
{
	ktime_t *start_time, *avg_time, end_time, duration, prev_duration, sum;
	struct stats_wakeup_time *min_time, *max_time, *last_time, prev;
	u64 avg_ns;
	char buf[32] = {0};
	unsigned int nr = 0;

	switch (state.event) {
	case PM_EVENT_RESUME:
		snprintf(buf, sizeof(buf), "%s", "resume time:");
		start_time = &resume_start_time;
		min_time = &suspend_stats.resume_min_time;
		max_time = &suspend_stats.resume_max_time;
		last_time = &suspend_stats.resume_last_time;
		avg_time = &suspend_stats.resume_avg_time;
		break;
	case PM_EVENT_SUSPEND:
		snprintf(buf, sizeof(buf), "%s", "suspend time:");
		start_time = &suspend_start_time;
		min_time = &suspend_stats.suspend_min_time;
		max_time = &suspend_stats.suspend_max_time;
		last_time = &suspend_stats.suspend_last_time;
		avg_time = &suspend_stats.suspend_avg_time;
		break;
	default:
		return;
	}

	if (!ktime_to_ns(*start_time))
		return;

	/* Calculate duration and update last time */
	end_time = ktime_get_boottime();
	prev = *last_time;
	prev_duration = ktime_sub(prev.end, prev.start);
	last_time->end = end_time;
	last_time->start = *start_time;
	duration = ktime_sub(end_time, *start_time);

	/* Update max time */
	if (ktime_compare(duration,
		ktime_sub(max_time->end, max_time->start)) > 0)
		*max_time = *last_time;

	/* Update min time */
	if (!ktime_to_ns(ktime_sub(min_time->end, min_time->start)))
		*min_time = *last_time;

	if (ktime_compare(duration,
		ktime_sub(min_time->end, min_time->start)) < 0)
		*min_time = *last_time;

	/* Compute the avg of current, previous and previous average times */
	if (ktime_to_ns(prev_duration))
		nr++;

	if (ktime_to_ns(*avg_time))
		nr++;

	sum = ktime_add(ktime_add(*avg_time, prev_duration), duration);
	avg_ns = div_u64(ktime_to_ns(sum), (nr + 1));
	*avg_time = ktime_set(0, avg_ns);
	*start_time = ktime_set(0, 0);

	pr_debug("%s\n%s  %llums\n%s  %llums\n %s  %llums\n%s %llums\n", buf,
			"  min:",
			ktime_to_ms(ktime_sub(min_time->end, min_time->start)),
			"  max:",
			ktime_to_ms(ktime_sub(max_time->end, max_time->start)),
			"  last:", ktime_to_ms(duration),
			"  avg:", ktime_to_ms(*avg_time));
	suspend_stats_queue.resume_done = 1;
	wake_up(&suspend_stats_queue.wait_queue);
}
EXPORT_SYMBOL_GPL(dpm_log_wakeup_stats);
#endif

static int dpm_run_callback(pm_callback_t cb, struct device *dev,
			    pm_message_t state, char *info)
{
+10 −0
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */

#ifndef _LINUX_PM_H
#define _LINUX_PM_H
@@ -703,6 +708,11 @@ extern int dpm_suspend_late(pm_message_t state);
extern int dpm_suspend(pm_message_t state);
extern int dpm_prepare(pm_message_t state);

#ifdef CONFIG_PM_WAKEUP_TIMES
extern void dpm_log_start_time(pm_message_t state);
extern void dpm_log_wakeup_stats(pm_message_t state);
#endif

extern void __suspend_report_result(const char *function, void *fn, int ret);

#define suspend_report_result(fn, ret)					\
+33 −0
Original line number Diff line number Diff line
/*
 * NOTE: This file has been modified by Sony Mobile Communications Inc.
 * Modifications are Copyright (c) 2014 Sony Mobile Communications Inc,
 * and licensed under the license of the file.
 */
#ifndef _LINUX_SUSPEND_H
#define _LINUX_SUSPEND_H

@@ -7,6 +12,10 @@
#include <linux/pm.h>
#include <linux/mm.h>
#include <linux/freezer.h>
#ifdef CONFIG_PM_WAKEUP_TIMES
#include <linux/ktime.h>
#include <linux/wait.h>
#endif
#include <asm/errno.h>

#ifdef CONFIG_VT
@@ -51,6 +60,20 @@ enum suspend_stat_step {
	SUSPEND_RESUME
};

#ifdef CONFIG_PM_WAKEUP_TIMES
struct stats_wakeup_time {
	ktime_t start;
	ktime_t end;
};

struct suspend_stats_queue {
	int resume_done;
	wait_queue_head_t wait_queue;
};

extern struct suspend_stats_queue suspend_stats_queue;
#endif

struct suspend_stats {
	int	success;
	int	fail;
@@ -69,6 +92,16 @@ struct suspend_stats {
	int	errno[REC_FAILED_NUM];
	int	last_failed_step;
	enum suspend_stat_step	failed_steps[REC_FAILED_NUM];
#ifdef CONFIG_PM_WAKEUP_TIMES
	struct stats_wakeup_time suspend_min_time;
	struct stats_wakeup_time suspend_max_time;
	struct stats_wakeup_time suspend_last_time;
	ktime_t suspend_avg_time;
	struct stats_wakeup_time resume_min_time;
	struct stats_wakeup_time resume_max_time;
	struct stats_wakeup_time resume_last_time;
	ktime_t resume_avg_time;
#endif
};

extern struct suspend_stats suspend_stats;
+19 −0
Original line number Diff line number Diff line
@@ -211,6 +211,18 @@ config DPM_WATCHDOG_TIMEOUT
	default 60
	depends on DPM_WATCHDOG

config PM_WAKEUP_TIMES
	bool "Log time taken for device wakeup"
	def_bool y
	depends on PM && PM_SLEEP && DEBUG_FS
	---help---
	  This enables code that calculates the total time spent for device
	  suspend and resume. These statistics are then logged to
	  <debugfs>/suspend_stats.

	  The statistics include minimum, maximum, average and the most recent
	  times for resume and suspend.

config PM_TRACE
	bool
	help
@@ -322,3 +334,10 @@ config PM_GENERIC_DOMAINS_OF

config CPU_PM
	bool

config WAKEUP_IRQ_DEBUG
	bool "Debug info of wakeup irq"
	default n
	---help---
	  This enables debug information about wakeup interrupts using
	  sysfs (/sys/kernel/).
+1 −0
Original line number Diff line number Diff line
@@ -14,3 +14,4 @@ obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o

obj-$(CONFIG_SUSPEND)	+= wakeup_reason.o
obj-$(CONFIG_WAKEUP_IRQ_DEBUG) += wakeup_irq_debug.o
Loading