From 520bc0723d8046c97b43c41080a425f007e89b31 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Wed, 19 Feb 2014 15:30:47 -0800 Subject: Power: add an API to log wakeup reasons Add API log_wakeup_reason() and expose it to userspace via sysfs path /sys/kernel/wakeup_reasons/last_resume_reason Change-Id: I81addaf420f1338255c5d0638b0d244a99d777d1 Signed-off-by: Ruchi Kandoi --- kernel/power/Makefile | 2 + kernel/power/wakeup_reason.c | 132 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 kernel/power/wakeup_reason.c (limited to 'kernel') diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 8450b85d33c0..74c713ba61b0 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -14,3 +14,5 @@ obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o obj-$(CONFIG_SUSPEND_TIME) += suspend_time.o obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o + +obj-$(CONFIG_SUSPEND) += wakeup_reason.o diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c new file mode 100644 index 000000000000..ae9bfece9d9a --- /dev/null +++ b/kernel/power/wakeup_reason.c @@ -0,0 +1,132 @@ +/* + * kernel/power/wakeup_reason.c + * + * Logs the reasons which caused the kernel to resume from + * the suspend mode. + * + * Copyright (C) 2014 Google, Inc. + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MAX_WAKEUP_REASON_IRQS 32 +static int irq_list[MAX_WAKEUP_REASON_IRQS]; +static int irq_count; +static struct kobject *wakeup_reason; +static spinlock_t resume_reason_lock; + +static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int irq_no, buf_offset = 0; + struct irq_desc *desc; + spin_lock(&resume_reason_lock); + for (irq_no = 0; irq_no < irq_count; irq_no++) { + desc = irq_to_desc(irq_list[irq_no]); + if (desc && desc->action && desc->action->name) + buf_offset += sprintf(buf + buf_offset, "%d %s\n", + irq_list[irq_no], desc->action->name); + else + buf_offset += sprintf(buf + buf_offset, "%d\n", + irq_list[irq_no]); + } + spin_unlock(&resume_reason_lock); + return buf_offset; +} + +static struct kobj_attribute resume_reason = __ATTR(last_resume_reason, 0666, + reason_show, NULL); + +static struct attribute *attrs[] = { + &resume_reason.attr, + NULL, +}; +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +/* + * logs all the wake up reasons to the kernel + * stores the irqs to expose them to the userspace via sysfs + */ +void log_wakeup_reason(int irq) +{ + struct irq_desc *desc; + desc = irq_to_desc(irq); + if (desc && desc->action && desc->action->name) + printk(KERN_INFO "Resume caused by IRQ %d, %s\n", irq, + desc->action->name); + else + printk(KERN_INFO "Resume caused by IRQ %d\n", irq); + + spin_lock(&resume_reason_lock); + irq_list[irq_count++] = irq; + spin_unlock(&resume_reason_lock); +} + +/* Detects a suspend and clears all the previous wake up reasons*/ +static int wakeup_reason_pm_event(struct notifier_block *notifier, + unsigned long pm_event, void *unused) +{ + switch (pm_event) { + case PM_SUSPEND_PREPARE: + spin_lock(&resume_reason_lock); + irq_count = 0; + spin_unlock(&resume_reason_lock); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block wakeup_reason_pm_notifier_block = { + .notifier_call = wakeup_reason_pm_event, +}; + +/* Initializes the sysfs parameter + * registers the pm_event notifier + */ +void __init wakeup_reason_init(void) +{ + int retval; + spin_lock_init(&resume_reason_lock); + retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); + if (retval) + printk(KERN_WARNING "[%s] failed to register PM notifier %d\n", + __func__, retval); + + wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj); + if (!wakeup_reason) { + printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n", + __func__); + return; + } + retval = sysfs_create_group(wakeup_reason, &attr_group); + if (retval) { + kobject_put(wakeup_reason); + printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n", + __func__, retval); + } +} + +late_initcall(wakeup_reason_init); -- cgit v1.2.3 From 39129eff0f76e66f50ad604c5a68630816acb7ba Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 20 Feb 2014 19:47:38 -0800 Subject: POWER: fix compile warnings in log_wakeup_reason Change I81addaf420f1338255c5d0638b0d244a99d777d1 introduced compile warnings, fix these. Change-Id: I05482a5335599ab96c0a088a7d175c8d4cf1cf69 Signed-off-by: Ruchi Kandoi --- kernel/power/wakeup_reason.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index ae9bfece9d9a..82e69fe52d0b 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -35,7 +35,7 @@ static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count) + char *buf) { int irq_no, buf_offset = 0; struct irq_desc *desc; @@ -106,7 +106,7 @@ static struct notifier_block wakeup_reason_pm_notifier_block = { /* Initializes the sysfs parameter * registers the pm_event notifier */ -void __init wakeup_reason_init(void) +int __init wakeup_reason_init(void) { int retval; spin_lock_init(&resume_reason_lock); @@ -119,7 +119,7 @@ void __init wakeup_reason_init(void) if (!wakeup_reason) { printk(KERN_WARNING "[%s] failed to create a sysfs kobject\n", __func__); - return; + return 1; } retval = sysfs_create_group(wakeup_reason, &attr_group); if (retval) { @@ -127,6 +127,7 @@ void __init wakeup_reason_init(void) printk(KERN_WARNING "[%s] failed to create a sysfs group %d\n", __func__, retval); } + return 0; } late_initcall(wakeup_reason_init); -- cgit v1.2.3 From 8b531976d51c33d5ef83ca2637b08afc2ed51802 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Fri, 7 Mar 2014 12:54:30 -0800 Subject: Power: Add guard condition for maximum wakeup reasons Ensure the array for the wakeup reason IRQs does not overflow. Change-Id: Iddc57a3aeb1888f39d4e7b004164611803a4d37c Signed-off-by: Ruchi Kandoi (cherry picked from commit b5ea40cdfcf38296535f931a7e5e7bf47b6fad7f) --- kernel/power/wakeup_reason.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 82e69fe52d0b..caf44213b14c 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -79,6 +79,13 @@ void log_wakeup_reason(int irq) printk(KERN_INFO "Resume caused by IRQ %d\n", irq); spin_lock(&resume_reason_lock); + if (irq_count == MAX_WAKEUP_REASON_IRQS) { + spin_unlock(&resume_reason_lock); + printk(KERN_WARNING "Resume caused by more than %d IRQs\n", + MAX_WAKEUP_REASON_IRQS); + return; + } + irq_list[irq_count++] = irq; spin_unlock(&resume_reason_lock); } -- cgit v1.2.3 From c9331cabfdfec4b8b0086ed155bb28e46330b14f Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Mon, 10 Mar 2014 14:21:30 -0700 Subject: power: wakeup_reason: rename irq_count to irqcount On x86, irq_count conflicts with a declaration in arch/x86/include/asm/processor.h Change-Id: I3e4fde0ff64ef59ff5ed2adc0ea3a644641ee0b7 Signed-off-by: Greg Hackmann --- kernel/power/wakeup_reason.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index caf44213b14c..188a6bfacf5a 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -30,7 +30,7 @@ #define MAX_WAKEUP_REASON_IRQS 32 static int irq_list[MAX_WAKEUP_REASON_IRQS]; -static int irq_count; +static int irqcount; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; @@ -40,7 +40,7 @@ static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, int irq_no, buf_offset = 0; struct irq_desc *desc; spin_lock(&resume_reason_lock); - for (irq_no = 0; irq_no < irq_count; irq_no++) { + for (irq_no = 0; irq_no < irqcount; irq_no++) { desc = irq_to_desc(irq_list[irq_no]); if (desc && desc->action && desc->action->name) buf_offset += sprintf(buf + buf_offset, "%d %s\n", @@ -79,14 +79,14 @@ void log_wakeup_reason(int irq) printk(KERN_INFO "Resume caused by IRQ %d\n", irq); spin_lock(&resume_reason_lock); - if (irq_count == MAX_WAKEUP_REASON_IRQS) { + if (irqcount == MAX_WAKEUP_REASON_IRQS) { spin_unlock(&resume_reason_lock); printk(KERN_WARNING "Resume caused by more than %d IRQs\n", MAX_WAKEUP_REASON_IRQS); return; } - irq_list[irq_count++] = irq; + irq_list[irqcount++] = irq; spin_unlock(&resume_reason_lock); } @@ -97,7 +97,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier, switch (pm_event) { case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); - irq_count = 0; + irqcount = 0; spin_unlock(&resume_reason_lock); break; default: -- cgit v1.2.3 From 37a591d407084b967bb49acc3fe21c446b075d55 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Fri, 18 Apr 2014 14:07:28 -0700 Subject: prctl: adds PR_SET_TIMERSLACK_PID for setting timer slack of an arbitrary thread. Second argument is similar to PR_SET_TIMERSLACK, if non-zero then the slack is set to that value otherwise sets it to the default for the thread. Takes PID of the thread as the third argument. This allows power/performance management software to set timer slack for other threads according to its policy for the thread (such as when the thread is designated foreground vs. background activity) Change-Id: I744d451ff4e60dae69f38f53948ff36c51c14a3f Signed-off-by: Ruchi Kandoi --- kernel/sys.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'kernel') diff --git a/kernel/sys.c b/kernel/sys.c index 126b7c939d1f..875529e936ab 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -2252,6 +2253,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5) { struct task_struct *me = current; + struct task_struct *tsk; unsigned char comm[sizeof(me->comm)]; long error; @@ -2375,6 +2377,23 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, else return -EINVAL; break; + case PR_SET_TIMERSLACK_PID: + rcu_read_lock(); + tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns); + if (tsk == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + get_task_struct(tsk); + rcu_read_unlock(); + if (arg2 <= 0) + tsk->timer_slack_ns = + tsk->default_timer_slack_ns; + else + tsk->timer_slack_ns = arg2; + put_task_struct(tsk); + error = 0; + break; default: return -EINVAL; } -- cgit v1.2.3 From 70dc3ed48fb6c02d2c651505d41f8988570f2f81 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Thu, 24 Apr 2014 14:31:57 -0700 Subject: Power: Changes the permission to read only for sysfs file /sys/kernel/wakeup_reasons/last_resume_reason Change-Id: I8ac568a7cb58c31decd379195de517ff3c6f9c65 Signed-off-by: Ruchi Kandoi --- kernel/power/wakeup_reason.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 188a6bfacf5a..187e4e9105fb 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -34,7 +34,7 @@ static int irqcount; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; -static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, +static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int irq_no, buf_offset = 0; @@ -53,8 +53,7 @@ static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, return buf_offset; } -static struct kobj_attribute resume_reason = __ATTR(last_resume_reason, 0666, - reason_show, NULL); +static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason); static struct attribute *attrs[] = { &resume_reason.attr, -- cgit v1.2.3