From patchwork Wed Mar 12 19:46:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruchi Kandoi X-Patchwork-Id: 3820671 Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 349A0BF540 for ; Wed, 12 Mar 2014 19:47:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 05F1A202F8 for ; Wed, 12 Mar 2014 19:47:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CDDBC202E5 for ; Wed, 12 Mar 2014 19:47:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751230AbaCLTrI (ORCPT ); Wed, 12 Mar 2014 15:47:08 -0400 Received: from mail-ie0-f201.google.com ([209.85.223.201]:57003 "EHLO mail-ie0-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750882AbaCLTrG (ORCPT ); Wed, 12 Mar 2014 15:47:06 -0400 Received: by mail-ie0-f201.google.com with SMTP id rd18so2213903iec.4 for ; Wed, 12 Mar 2014 12:47:05 -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=Dw+ggZlXSx3eQwN9InJrAi+js5Tp/bALEvEuCCZAqaI=; b=bMf5mYnXP4prSFNHN8c4+r0u/eaGau39EIGFuFDnSpoTOXYsp+zL+dUYkdJg3/WRQY qfxV0MHjwuiIjeNTbZ60QPKZEIVFwtK6wgMCRKX/qoP8MLu6XL0IFhkk+5utVTYn4PEi /8rSKcpbkZGoOFEDsavMm0UnxhxtZsI9F56uVFdzIGdOqh8/VcvYyUaW7gmJ9eDOKxWB h1V5u/lKAAoe29Pdzx2QIdsBzMtIV0OdQz7E5aXsV36eQ7UObFlvBSALFMse2/Lt1jFc VMUtEM4rWocAYoyF7UeZ2pQTp6/lhCB0bepGQLqW+G0OJZy1bCpL5ZWRV/NSJw+RwoIY Rucw== 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=Dw+ggZlXSx3eQwN9InJrAi+js5Tp/bALEvEuCCZAqaI=; b=iSq0LHfm7D+g6/xVOaPmOIN0I2bKVMK8HXHyiYRFCY2aVeoraM/WkTvBj4JD8MDu7o 8W+sdo7+7Zdaqvt8Zo+QG4mqf/8TWgDpiBbdW3amfRQ4Z8NUNO9sO7tDt2YwduEr6Ec7 sjTqzsJNYhrU/uzdiDhfEXOcpZTMAHbKylI/x5Udzpj+5X6OSBzBEF9XVVkEJVpgCATY PPYtKV/fiW4SHUzqFyam0vTQP8z8dQKPLxbxDmAwXyfgpDr7BIiVcwjkmq76h4+jGzvf 96pbDQKH/3Ih+OcuZ+cShjHng1dPmoO05Xv+B15oBeyvUfyuqWGRyyksGDETzJvAmKNr yJEQ== X-Gm-Message-State: ALoCoQngW9ogaVR//TzRBVMbYwuWSQZDiitIV6oDV+avP0oIB3+efmsonhpPcuSo31ynrMm/xRnAaT8W8D+i/OpasqVfdVgaseUXhbPGmcKo+9Bgfmbbbqu/n0+81JYxD6miE1M/AMQ5gJ/BYPL/T5kt4lBJOFMr5tVtS/nGlDy17/ROitvGe6DGV4fgvsL1LG9t6yhcAOheDFVr4AKajB3ZuuZiGC/3Rg== X-Received: by 10.50.78.231 with SMTP id e7mr13125476igx.5.1394653625577; Wed, 12 Mar 2014 12:47:05 -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 f21si238574yhn.2.2014.03.12.12.47.05 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 12 Mar 2014 12:47:05 -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 54E425A4290; Wed, 12 Mar 2014 12:47:05 -0700 (PDT) Received: by kandoiruchi.mtv.corp.google.com (Postfix, from userid 235580) id CDCCB121CFB; Wed, 12 Mar 2014 12:47:04 -0700 (PDT) From: Ruchi Kandoi To: linux-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 v3] power: add an API to log wakeup reasons Date: Wed, 12 Mar 2014 12:46:38 -0700 Message-Id: <1394653598-17143-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=ham 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 For power management diagnostic purposes, it is often useful to know what interrupts are frequently waking the system from low power suspend mode, especially on battery-powered consumer electronics devices that are expected to spend much of their time in low-power suspend while not in active use. For example, reduced battery life on a mobile phone may be caused in part by frequent wakeups by broadcast traffic on a busy wireless LAN even while the screen is off and the phone not in active use. Add API log_wakeup_reason() exposes it to userspace via the sysfs path /sys/kernel/wakeup_reasons/last_resume_reason. This API would be called from the paltform specific, or from the driver for the interrupt controller, when the system resumes because of an IRQ. It logs the reasons which caused the system to wakeup from the low-power mode. This information can be collected by userspace as part of the accounting kept on power consumption. Signed-off-by: Ruchi Kandoi Signed-off-by: Greg Hackmann --- commit message changed for clarity --- 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);