-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: ShivamKumarJha <[email protected]>
- Loading branch information
1 parent
41ece96
commit b199795
Showing
3 changed files
with
92 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* drivers/base/power/wakeup.c - System wakeup events framework | ||
* | ||
* Copyright (c) 2010 Rafael J. Wysocki <[email protected]>, Novell Inc. | ||
* Copyright (C) 2021 XiaoMi, Inc. | ||
* | ||
* This file is released under the GPLv2. | ||
*/ | ||
|
@@ -22,7 +23,7 @@ | |
#include <linux/irq.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/irqdesc.h> | ||
|
||
#include <linux/wakeup_reason.h> | ||
#include "power.h" | ||
|
||
#ifndef CONFIG_SUSPEND | ||
|
@@ -38,10 +39,11 @@ bool events_check_enabled __read_mostly; | |
|
||
/* First wakeup IRQ seen by the kernel in the last cycle. */ | ||
unsigned int pm_wakeup_irq __read_mostly; | ||
extern void system_sleep_status_print_enabled(void); | ||
|
||
/* If greater than 0 and the system is suspending, terminate the suspend. */ | ||
static atomic_t pm_abort_suspend __read_mostly; | ||
|
||
static struct delayed_work wakelock_work; | ||
/* | ||
* Combined counters of registered wakeup events and wakeup events in progress. | ||
* They need to be modified together atomically, so it's better to use one | ||
|
@@ -902,7 +904,7 @@ void pm_print_active_wakeup_sources(void) | |
srcuidx = srcu_read_lock(&wakeup_srcu); | ||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) { | ||
if (ws->active) { | ||
pr_debug("active wakeup source: %s\n", ws->name); | ||
pr_info("active wakeup source: %s\n", ws->name); | ||
active = 1; | ||
} else if (!active && | ||
(!last_activity_ws || | ||
|
@@ -913,7 +915,7 @@ void pm_print_active_wakeup_sources(void) | |
} | ||
|
||
if (!active && last_activity_ws) | ||
pr_debug("last active wakeup source: %s\n", | ||
pr_info("last active wakeup source: %s\n", | ||
last_activity_ws->name); | ||
srcu_read_unlock(&wakeup_srcu, srcuidx); | ||
} | ||
|
@@ -927,6 +929,7 @@ EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); | |
* since the old value was stored. Also return true if the current number of | ||
* wakeup events being processed is different from zero. | ||
*/ | ||
bool wakeup_irq_abort_suspend; | ||
bool pm_wakeup_pending(void) | ||
{ | ||
unsigned long flags; | ||
|
@@ -956,6 +959,7 @@ bool pm_wakeup_pending(void) | |
void pm_system_wakeup(void) | ||
{ | ||
atomic_inc(&pm_abort_suspend); | ||
wakeup_irq_abort_suspend = true; | ||
s2idle_wake(); | ||
} | ||
EXPORT_SYMBOL_GPL(pm_system_wakeup); | ||
|
@@ -968,6 +972,7 @@ void pm_system_cancel_wakeup(void) | |
void pm_wakeup_clear(bool reset) | ||
{ | ||
pm_wakeup_irq = 0; | ||
wakeup_irq_abort_suspend = false; | ||
if (reset) | ||
atomic_set(&pm_abort_suspend, 0); | ||
} | ||
|
@@ -991,6 +996,7 @@ void pm_system_irq_wakeup(unsigned int irq_number) | |
} | ||
pm_wakeup_irq = irq_number; | ||
pm_system_wakeup(); | ||
log_irq_wakeup_reason(irq_number); | ||
} | ||
} | ||
|
||
|
@@ -1135,46 +1141,103 @@ static int print_wakeup_source_stats(struct seq_file *m, | |
return 0; | ||
} | ||
|
||
static void *wakeup_sources_stats_seq_start(struct seq_file *m, loff_t *pos) | ||
{ | ||
struct wakeup_source *ws; | ||
loff_t n = *pos; | ||
int *srcuidx = m->private; | ||
|
||
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"); | ||
} | ||
|
||
*srcuidx = srcu_read_lock(&wakeup_srcu); | ||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) { | ||
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); | ||
|
||
list_for_each_entry_continue_rcu(ws, &wakeup_sources, entry) { | ||
next_ws = ws; | ||
break; | ||
} | ||
|
||
return next_ws; | ||
} | ||
|
||
static void wakeup_sources_stats_seq_stop(struct seq_file *m, void *v) | ||
{ | ||
int *srcuidx = m->private; | ||
|
||
srcu_read_unlock(&wakeup_srcu, *srcuidx); | ||
} | ||
|
||
/** | ||
* wakeup_sources_stats_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_show(struct seq_file *m, void *unused) | ||
static int wakeup_sources_stats_seq_show(struct seq_file *m, void *v) | ||
{ | ||
struct wakeup_source *ws; | ||
int srcuidx; | ||
|
||
seq_puts(m, "name\t\t\t\t\tactive_count\tevent_count\twakeup_count\t" | ||
"expire_count\tactive_since\ttotal_time\tmax_time\t" | ||
"last_change\tprevent_suspend_time\n"); | ||
struct wakeup_source *ws = v; | ||
|
||
srcuidx = srcu_read_lock(&wakeup_srcu); | ||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) | ||
print_wakeup_source_stats(m, ws); | ||
srcu_read_unlock(&wakeup_srcu, srcuidx); | ||
print_wakeup_source_stats(m, ws); | ||
|
||
print_wakeup_source_stats(m, &deleted_ws); | ||
|
||
return 0; | ||
} | ||
|
||
void print_active_wakelock(struct work_struct *work) | ||
|
||
{ | ||
|
||
pm_print_active_wakeup_sources(); | ||
#ifdef CONFIG_DEBUG_FS | ||
system_sleep_status_print_enabled(); | ||
#endif | ||
schedule_delayed_work(&wakelock_work, 18000); | ||
|
||
} | ||
|
||
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 wakeup_sources_stats_open(struct inode *inode, struct file *file) | ||
{ | ||
return single_open(file, wakeup_sources_stats_show, NULL); | ||
return seq_open_private(file, &wakeup_sources_stats_seq_ops, sizeof(int)); | ||
} | ||
|
||
static const struct file_operations wakeup_sources_stats_fops = { | ||
.owner = THIS_MODULE, | ||
.open = wakeup_sources_stats_open, | ||
.read = seq_read, | ||
.llseek = seq_lseek, | ||
.release = single_release, | ||
.release = seq_release_private, | ||
}; | ||
|
||
static int __init wakeup_sources_debugfs_init(void) | ||
{ | ||
wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources", | ||
S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops); | ||
INIT_DELAYED_WORK(&wakelock_work, print_active_wakelock); | ||
schedule_delayed_work(&wakelock_work, 1); | ||
return 0; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters