From patchwork Wed Mar 12 02:02:47 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruchi Kandoi X-Patchwork-Id: 3815211 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9B0649F2BB for ; Wed, 12 Mar 2014 02:02:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5D2152028D for ; Wed, 12 Mar 2014 02:02:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3226B201F7 for ; Wed, 12 Mar 2014 02:02:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756459AbaCLCCx (ORCPT ); Tue, 11 Mar 2014 22:02:53 -0400 Received: from mail-ob0-f202.google.com ([209.85.214.202]:60864 "EHLO mail-ob0-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756456AbaCLCCu (ORCPT ); Tue, 11 Mar 2014 22:02:50 -0400 Received: by mail-ob0-f202.google.com with SMTP id wo20so1997415obc.1 for ; Tue, 11 Mar 2014 19:02:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=QdyO+TNxCYGIMnHL7ZTDhMlEINKYKBSbtfGszGA6pbo=; b=J4I6wFTdxxyhpCzyag5ymyBOJXNpqTfEufqgnGre0MNqFGDzWS3wJsjRMn1a4TJNgV AYANzDPEuIUKB3BfQsCEglsPrGNn+mhSLX/Kl0c8jYr8HS2xbW/RPj0VTp8pHp+rU7nR MNzOwWgNGomrunoKiLN2Yi8kHX2/EJRxZQNySc5Azdp/0aTu21umktk1St5pctAf66tW R2Pou2UkoPGEgbrXMie8x8/7uOjrgIHpX+ncXjIIsKuKOzfiBJNYnbAgM97I9z1IdI/Z dy3q7bLH+XqJ1P7XS8b8TRjLnv+9JplXuNeufI9I/58mFBYy4xDNkuLeZHu4B6TwM2G1 U00w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=QdyO+TNxCYGIMnHL7ZTDhMlEINKYKBSbtfGszGA6pbo=; b=fIih85ClD7iMGgX7PPPVx/PVEM2zIKvay5FwZIlqXw73JuGDmY7GgvBAFHdaYtSeEK iHtN/l/L26vdOHfV/g3IDNjCLF6DI9tUmwpba5I3oEhZAQfBdTVDvuh/QWyrYsuWNWKd WZRi12amnu6TRX0W4Ek5QpAiPa/G3vtmXt9ansAz0EUfmAdml3+ZVaardWj60cRatWPw t637uNi0UbSWe4txH2+TNx12bUefcY5obwRFGzLi/ix1OT80uu86lgBUuzl5QB5k1iJO g8jF3LP4ODmMVrp35+LOeYDgUBP8Hi8R6VBUyY6rbMxCo/vfQuIfPrILnWZyaEyd2EgV nQZw== X-Gm-Message-State: ALoCoQkNlifSEQabTRDvkMCEx15HRLp1SyS7quteoC4QOCLW5LyEKEcShSZ7wF+tRXkvLhFSwexFWoy3oJxUUyQVmAFLZSYc8fWWRjdAtU0feHkcAdh+VE7uIt+mjidxphnpKKXrVEdp7kJIgJyGi2gRHbbHsR5hICSi/ghGU6Z/9Klr3cH6vWg6+C1/HE3X9KvRsm3Pf31xp87Pc+lL5dCpGWt0pqyPqQ== X-Received: by 10.182.118.194 with SMTP id ko2mr16892010obb.32.1394589770161; Tue, 11 Mar 2014 19:02:50 -0700 (PDT) Received: from corp2gmr1-2.hot.corp.google.com (corp2gmr1-2.hot.corp.google.com [172.24.189.93]) by gmr-mx.google.com with ESMTPS id d9si3789887yhl.2.2014.03.11.19.02.50 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 11 Mar 2014 19:02:50 -0700 (PDT) Received: from kandoiruchi.mtv.corp.google.com (kandoiruchi.mtv.corp.google.com [172.18.120.123]) by corp2gmr1-2.hot.corp.google.com (Postfix) with ESMTP id D07AC5A42C3; Tue, 11 Mar 2014 19:02:49 -0700 (PDT) Received: by kandoiruchi.mtv.corp.google.com (Postfix, from userid 235580) id 676411209D8; Tue, 11 Mar 2014 19:02:49 -0700 (PDT) From: Ruchi Kandoi To: inux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Cc: rjw@rjwysocki.net, ghackmann@google.com, john.stultz@linaro.org, toddpoynor@google.com, Ruchi Kandoi Subject: [PATCH v2] power: add an API to log wakeup reasons Date: Tue, 11 Mar 2014 19:02:47 -0700 Message-Id: <1394589767-16829-1-git-send-email-kandoiruchi@google.com> X-Mailer: git-send-email 1.9.0.279.gdc9e3eb Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add API log_wakeup_reason() and expose it to userspace via sysfs path /sys/kernel/wakeup_reasons/last_resume_reason This is useful for power management diagnostic purposes. Signed-off-by: Ruchi Kandoi Signed-off-by: Greg Hackmann --- printk changed to pr_warn/pr_info added pr_fmt(fmt) "wakeup_reason:" fmt guard condition for MAX_WAKEUP_REASON_IRQ changed from == to >= --- include/linux/wakeup_reason.h | 23 +++++++ kernel/power/Makefile | 2 +- kernel/power/wakeup_reason.c | 141 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 include/linux/wakeup_reason.h create mode 100644 kernel/power/wakeup_reason.c diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h new file mode 100644 index 0000000..7ce50f0 --- /dev/null +++ b/include/linux/wakeup_reason.h @@ -0,0 +1,23 @@ +/* + * include/linux/wakeup_reason.h + * + * Logs the reason 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. + */ + +#ifndef _LINUX_WAKEUP_REASON_H +#define _LINUX_WAKEUP_REASON_H + +void log_wakeup_reason(int irq); + +#endif /* _LINUX_WAKEUP_REASON_H */ diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 29472bf..f98f021 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -5,7 +5,7 @@ obj-y += qos.o obj-$(CONFIG_PM) += main.o obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o obj-$(CONFIG_FREEZER) += process.o -obj-$(CONFIG_SUSPEND) += suspend.o +obj-$(CONFIG_SUSPEND) += suspend.o wakeup_reason.o obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \ block_io.o diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c new file mode 100644 index 0000000..a21c592 --- /dev/null +++ b/kernel/power/wakeup_reason.c @@ -0,0 +1,141 @@ +/* + * 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. + */ +#define pr_fmt(fmt) "wakeup_reason:" fmt + +#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 irqcount; +static struct kobject *wakeup_reason; +static spinlock_t resume_reason_lock; + +static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int irq_no, buf_offset = 0; + struct irq_desc *desc; + spin_lock(&resume_reason_lock); + 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", + 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) + pr_info("Resume caused by IRQ %d, %s\n", irq, + desc->action->name); + else + pr_info("Resume caused by IRQ %d\n", irq); + + spin_lock(&resume_reason_lock); + if (irqcount >= MAX_WAKEUP_REASON_IRQS) { + spin_unlock(&resume_reason_lock); + pr_warn("Resume caused by more than %d IRQs\n", + MAX_WAKEUP_REASON_IRQS); + return; + } + + irq_list[irqcount++] = 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); + irqcount = 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 + */ +int __init wakeup_reason_init(void) +{ + int retval; + spin_lock_init(&resume_reason_lock); + retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); + if (retval) + pr_warn("%s: failed to register PM notifier %d\n", + __func__, retval); + + wakeup_reason = kobject_create_and_add("wakeup_reasons", kernel_kobj); + if (!wakeup_reason) { + pr_warn("%s: failed to create a sysfs kobject\n", + __func__); + return 1; + } + retval = sysfs_create_group(wakeup_reason, &attr_group); + if (retval) { + kobject_put(wakeup_reason); + pr_warn("%s: failed to create a sysfs group %d\n", + __func__, retval); + } + return 0; +} + +late_initcall(wakeup_reason_init);