From patchwork Sat Sep 3 14:39:11 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Santosh Shilimkar X-Patchwork-Id: 1123322 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p83EfqgN029578 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Sat, 3 Sep 2011 14:42:13 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QzrPd-0006pR-1L; Sat, 03 Sep 2011 14:41:38 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QzrPE-0000TN-DQ; Sat, 03 Sep 2011 14:41:12 +0000 Received: from bear.ext.ti.com ([192.94.94.41]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QzrO1-0008Ut-Or for linux-arm-kernel@lists.infradead.org; Sat, 03 Sep 2011 14:40:01 +0000 Received: from dbdp20.itg.ti.com ([172.24.170.38]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id p83EdUac023605 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sat, 3 Sep 2011 09:39:32 -0500 Received: from dbde71.ent.ti.com (localhost [127.0.0.1]) by dbdp20.itg.ti.com (8.13.8/8.13.8) with ESMTP id p83EdTLk007252; Sat, 3 Sep 2011 20:09:29 +0530 (IST) Received: from dbdp31.itg.ti.com (172.24.170.98) by DBDE71.ent.ti.com (172.24.170.149) with Microsoft SMTP Server id 8.3.106.1; Sat, 3 Sep 2011 20:09:29 +0530 Received: from ula0393909.apr.dhcp.ti.com (ula0393909.apr.dhcp.ti.com [172.24.137.49]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with ESMTP id p83EdI6X019532; Sat, 3 Sep 2011 20:09:28 +0530 (IST) From: Santosh Shilimkar To: Subject: [PATCH v2 1/5] cpu_pm: Add cpu power management notifiers Date: Sat, 3 Sep 2011 20:09:11 +0530 Message-ID: <1315060755-4613-2-git-send-email-santosh.shilimkar@ti.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1315060755-4613-1-git-send-email-santosh.shilimkar@ti.com> References: <1315060755-4613-1-git-send-email-santosh.shilimkar@ti.com> MIME-Version: 1.0 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110903_103958_172910_D4E63A63 X-CRM114-Status: GOOD ( 22.76 ) X-Spam-Score: -2.8 (--) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-2.8 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [192.94.94.41 listed in list.dnswl.org] -0.5 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain Cc: khilman@ti.com, linux@arm.linux.org.uk, linux-kernel@vger.kernel.org, rjw@sisk.pl, Santosh Shilimkar , ccross@android.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sat, 03 Sep 2011 14:42:13 +0000 (UTC) From: Colin Cross During some CPU power modes entered during idle, hotplug and suspend, peripherals located in the CPU power domain, such as the GIC, localtimers, and VFP, may be powered down. Add a notifier chain that allows drivers for those peripherals to be notified before and after they may be reset. Signed-off-by: Colin Cross [santosh.shilimkar@ti.com: Rebased against 3.1-rc3] Signed-off-by: Santosh Shilimkar Tested-by: Kevin Hilman --- include/linux/cpu_pm.h | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ kernel/Makefile | 1 + kernel/cpu_pm.c | 115 ++++++++++++++++++++++++++++++++++++++++++++ kernel/power/Kconfig | 4 ++ 4 files changed, 243 insertions(+), 0 deletions(-) create mode 100644 include/linux/cpu_pm.h create mode 100644 kernel/cpu_pm.c diff --git a/include/linux/cpu_pm.h b/include/linux/cpu_pm.h new file mode 100644 index 0000000..3c880cb --- /dev/null +++ b/include/linux/cpu_pm.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * Author: + * Colin Cross + * + * 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_CPU_PM_H +#define _LINUX_CPU_PM_H + +#include +#include + +/* + * When a CPU goes to a low power state that turns off power to the CPU's + * power domain, the contents of some blocks (floating point coprocessors, + * interrutp controllers, caches, timers) in the same power domain can + * be lost. The cpm_pm notifiers provide a method for platform idle, suspend, + * and hotplug implementations to notify the drivers for these blocks that + * they may be reset. + * + * All cpu_pm notifications must be called with interrupts disabled. + * + * The notifications are split into two classes, CPU notifications and CPU + * cluster notifications. + * + * CPU notifications apply to a single CPU, and must be called on the affected + * CPU. They are used to save per-cpu context for affected blocks. + * + * CPU cluster notifications apply to all CPUs in a single power domain. They + * are used to save any global context for affected blocks, and must be called + * after all the CPUs in the power domain have been notified of the low power + * state. + * + */ + +/* + * Event codes passed as unsigned long val to notifier calls + */ +enum cpu_pm_event { + /* A single cpu is entering a low power state */ + CPU_PM_ENTER, + + /* A single cpu failed to enter a low power state */ + CPU_PM_ENTER_FAILED, + + /* A single cpu is exiting a low power state */ + CPU_PM_EXIT, + + /* A cpu power domain is entering a low power state */ + CPU_CLUSTER_PM_ENTER, + + /* A cpu power domain failed to enter a low power state */ + CPU_CLUSTER_PM_ENTER_FAILED, + + /* A cpu power domain is exiting a low power state */ + CPU_CLUSTER_PM_EXIT, +}; + +int cpu_pm_register_notifier(struct notifier_block *nb); +int cpu_pm_unregister_notifier(struct notifier_block *nb); + +/* + * cpm_pm_enter + * + * Notifies listeners that a single cpu is entering a low power state that may + * cause some blocks in the same power domain as the cpu to reset. + * + * Must be called on the affected cpu with interrupts disabled. Platform is + * responsible for ensuring that cpu_pm_enter is not called twice on the same + * cpu before cpu_pm_exit is called. + */ +int cpu_pm_enter(void); + +/* + * cpm_pm_exit + * + * Notifies listeners that a single cpu is exiting a low power state that may + * have caused some blocks in the same power domain as the cpu to reset. + * + * Must be called on the affected cpu with interrupts disabled. + */ +int cpu_pm_exit(void); + +/* + * cpm_cluster_pm_enter + * + * Notifies listeners that all cpus in a power domain are entering a low power + * state that may cause some blocks in the same power domain to reset. + * + * Must be called after cpu_pm_enter has been called on all cpus in the power + * domain, and before cpu_pm_exit has been called on any cpu in the power + * domain. + * + * Must be called with interrupts disabled. + */ +int cpu_cluster_pm_enter(void); + +/* + * cpm_pm_enter + * + * Notifies listeners that a single cpu is entering a low power state that may + * cause some blocks in the same power domain as the cpu to reset. + * + * Must be called after cpu_pm_enter has been called on all cpus in the power + * domain, and before cpu_pm_exit has been called on any cpu in the power + * domain. + * + * Must be called with interrupts disabled. + */ +int cpu_cluster_pm_exit(void); + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index eca595e..988cb3d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_RING_BUFFER) += trace/ obj-$(CONFIG_TRACEPOINTS) += trace/ obj-$(CONFIG_SMP) += sched_cpupri.o obj-$(CONFIG_IRQ_WORK) += irq_work.o +obj-$(CONFIG_CPU_PM) += cpu_pm.o obj-$(CONFIG_PERF_EVENTS) += events/ diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c new file mode 100644 index 0000000..54aa892 --- /dev/null +++ b/kernel/cpu_pm.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * Author: + * Colin Cross + * + * 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 + +static DEFINE_RWLOCK(cpu_pm_notifier_lock); +static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain); + +int cpu_pm_register_notifier(struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + write_lock_irqsave(&cpu_pm_notifier_lock, flags); + ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb); + write_unlock_irqrestore(&cpu_pm_notifier_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(cpu_pm_register_notifier); + +int cpu_pm_unregister_notifier(struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + write_lock_irqsave(&cpu_pm_notifier_lock, flags); + ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb); + write_unlock_irqrestore(&cpu_pm_notifier_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier); + +static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls) +{ + int ret; + + ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL, + nr_to_call, nr_calls); + + return notifier_to_errno(ret); +} + +int cpu_pm_enter(void) +{ + int nr_calls; + int ret = 0; + + read_lock(&cpu_pm_notifier_lock); + ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls); + if (ret) + cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL); + read_unlock(&cpu_pm_notifier_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(cpu_pm_enter); + +int cpu_pm_exit(void) +{ + int ret; + + read_lock(&cpu_pm_notifier_lock); + ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL); + read_unlock(&cpu_pm_notifier_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(cpu_pm_exit); + +int cpu_cluster_pm_enter(void) +{ + int nr_calls; + int ret = 0; + + read_lock(&cpu_pm_notifier_lock); + ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls); + if (ret) + cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL); + read_unlock(&cpu_pm_notifier_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter); + +int cpu_cluster_pm_exit(void) +{ + int ret; + + read_lock(&cpu_pm_notifier_lock); + ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL); + read_unlock(&cpu_pm_notifier_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 3744c59..f7456b4 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -235,3 +235,7 @@ config PM_GENERIC_DOMAINS config PM_GENERIC_DOMAINS_RUNTIME def_bool y depends on PM_RUNTIME && PM_GENERIC_DOMAINS + +config CPU_PM + def_bool y + depends on SUSPEND || CPU_IDLE