From patchwork Tue Sep 30 18:00:41 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guenter Roeck X-Patchwork-Id: 5006201 Return-Path: X-Original-To: patchwork-linux-sh@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 4FBCA9F327 for ; Tue, 30 Sep 2014 18:06:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DE15E200F2 for ; Tue, 30 Sep 2014 18:06:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 53BF32011D for ; Tue, 30 Sep 2014 18:06:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751914AbaI3SBO (ORCPT ); Tue, 30 Sep 2014 14:01:14 -0400 Received: from mail-pa0-f43.google.com ([209.85.220.43]:62580 "EHLO mail-pa0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751996AbaI3SBL (ORCPT ); Tue, 30 Sep 2014 14:01:11 -0400 Received: by mail-pa0-f43.google.com with SMTP id hz1so6811065pad.16 for ; Tue, 30 Sep 2014 11:01:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=P3ylumAPta+x4hSnbQJwyvsYf0XpihcWxEVOkYE6MRw=; b=KZbNSMifUIIHD5T4ASd6h2FoNr+Aay/O6HlqCcXMyAsAWIWz259QvWnft6lgqzzmW4 rWsV4AAgtLWzp1x4ydcBoy4nPIgKh4y0BYJ0enQnuE2NlnWIvd79eHViw+GnT4csni1X E4ZdvZqjmLI+OFTrmVn7dXHn/rdlGZsNgNvOby4JHpqVw3T4LOdYz26BvesxPovAENiS eTSZCDatkWnB5/V1FGxfGi1gDjFOU9C+xEHXzTxsj9DqgQjBBCpq3lff9D0kyGKvLOXE SIqxzSPco8t+GAEb92UeY7XnRhTZyh1P6dahB2y4Z6VMGkcg00esISuFTJIgRGVa+K6o euMQ== X-Received: by 10.68.186.33 with SMTP id fh1mr71827569pbc.105.1412100070546; Tue, 30 Sep 2014 11:01:10 -0700 (PDT) Received: from localhost (108-223-40-66.lightspeed.sntcca.sbcglobal.net. [108.223.40.66]) by mx.google.com with ESMTPSA id go1sm3990822pbd.77.2014.09.30.11.01.09 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 30 Sep 2014 11:01:10 -0700 (PDT) From: Guenter Roeck To: linux-kernel@vger.kernel.org Cc: linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-c6x-dev@linux-c6x.org, linux-ia64@vger.kernel.org, linux-metag@vger.kernel.org, linux-mips@linux-mips.org, linux-parisc@vger.kernel.org, linux-sh@vger.kernel.org, xen-devel@lists.xenproject.org, Guenter Roeck , Andrew Morton , Heiko Stuebner , Romain Perier , "James E.J. Bottomley" , Helge Deller , Russell King , Catalin Marinas , Will Deacon , Haavard Skinnemoen , Hans-Christian Egtvedt , Mark Salter , Aurelien Jacquiot , Tony Luck , Fenghua Yu , James Hogan , Ralf Baechle , Guan Xuetao , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , Konrad Rzeszutek Wilk , Boris Ostrovsky , Sebastian Reichel , Dmitry Eremin-Solenikov , David Woodhouse , Samuel Ortiz , Lee Jones Subject: [RFC PATCH 01/16] kernel: Add support for poweroff handler call chain Date: Tue, 30 Sep 2014 11:00:41 -0700 Message-Id: <1412100056-15517-2-git-send-email-linux@roeck-us.net> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1412100056-15517-1-git-send-email-linux@roeck-us.net> References: <1412100056-15517-1-git-send-email-linux@roeck-us.net> Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-2.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, RP_MATCHES_RCVD, T_DKIM_INVALID, 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 Various drivers implement architecture and/or device specific means to remove power from the system. For the most part, those drivers set the global variable pm_power_off to point to a function within the driver. This mechanism has a number of drawbacks. Typically only one scheme to remove power is supported (at least if pm_power_off is used). At least in theory there can be multiple means remove power, some of which may be less desirable. For example, some mechanisms may only power off the CPU or the CPU card, while another may power off the entire system. Others may really just execute a restart sequence or drop into the ROM monitor. Using pm_power_off can also be racy if the function pointer is set from a driver built as module, as the driver may be in the process of being unloaded when pm_power_off is called. If there are multiple poweroff handlers in the system, removing a module with such a handler may inadvertently reset the pointer to pm_power_off to NULL, leaving the system with no means to remove power. Introduce a system poweroff handler call chain to solve the described problems. This call chain is expected to be executed from the architecture specific machine_power_off() function. Drivers providing system poweroff functionality are expected to register with this call chain. By using the priority field in the notifier block, callers can control poweroff handler execution sequence and thus ensure that the poweroff handler with the optimal capabilities to remove power for a given system is called first. Cc: Andrew Morton cc: Heiko Stuebner Cc: Romain Perier Cc: James E.J. Bottomley Cc: Helge Deller Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Cc: Mark Salter Cc: Aurelien Jacquiot Cc: Tony Luck Cc: Fenghua Yu Cc: James Hogan Cc: Ralf Baechle Cc: Guan Xuetao Cc: Thomas Gleixner Cc: Ingo Molnar Cc: H. Peter Anvin Cc: Konrad Rzeszutek Wilk Cc: Boris Ostrovsky Cc: Sebastian Reichel Cc: Dmitry Eremin-Solenikov Cc: David Woodhouse Cc: Samuel Ortiz Cc: Lee Jones Signed-off-by: Guenter Roeck --- include/linux/reboot.h | 4 +++ kernel/reboot.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 67fc8fc..b172951 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -38,6 +38,10 @@ extern int reboot_force; extern int register_reboot_notifier(struct notifier_block *); extern int unregister_reboot_notifier(struct notifier_block *); +extern int register_poweroff_handler(struct notifier_block *); +extern int unregister_poweroff_handler(struct notifier_block *); +extern void do_kernel_poweroff(void); + extern int register_restart_handler(struct notifier_block *); extern int unregister_restart_handler(struct notifier_block *); extern void do_kernel_restart(char *cmd); diff --git a/kernel/reboot.c b/kernel/reboot.c index 5925f5a..bdfab65 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -106,6 +106,87 @@ EXPORT_SYMBOL(unregister_reboot_notifier); /* * Notifier list for kernel code which wants to be called + * to power off the system. + */ +static ATOMIC_NOTIFIER_HEAD(poweroff_handler_list); + +/** + * register_poweroff_handler - Register function to be called to power off + * the system + * @nb: Info about handler function to be called + * @nb->priority: Handler priority. Handlers should follow the + * following guidelines for setting priorities. + * 0: Poweroff handler of last resort, + * with limited poweroff capabilities + * 128: Default poweroff handler; use if no other + * poweroff handler is expected to be available, + * and/or if poweroff functionality is + * sufficient to poweroff the entire system + * 255: Highest priority poweroff handler, will + * preempt all other poweroff handlers + * + * Registers a function with code to be called to poweroff the + * system. + * + * Registered functions will be called from machine_power_off as last + * step of the poweroff sequence (if the architecture specific + * machine_power_off function calls do_kernel_poweroff - see below + * for details). + * Registered functions are expected to poweroff the system immediately. + * If more than one function is registered, the poweroff handler priority + * selects which function will be called first. + * + * Poweroff handlers are expected to be registered from non-architecture + * code, typically from drivers. A typical use case would be a system + * where poweroff functionality is provided through a mfd driver. Multiple + * poweroff handlers may exist; for example, one poweroff handler might + * poweroff the entire system, while another only powers off the CPU. + * In such cases, the poweroff handler which only powers off part of the + * hardware is expected to register with low priority to ensure that + * it only runs if no other means to poweroff the system is available. + * + * Currently always returns zero, as atomic_notifier_chain_register() + * always returns zero. + */ +int register_poweroff_handler(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&poweroff_handler_list, nb); +} +EXPORT_SYMBOL(register_poweroff_handler); + +/** + * unregister_poweroff_handler - Unregister previously registered + * poweroff handler + * @nb: Hook to be unregistered + * + * Unregisters a previously registered poweroff handler function. + * + * Returns zero on success, or %-ENOENT on failure. + */ +int unregister_poweroff_handler(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&poweroff_handler_list, nb); +} +EXPORT_SYMBOL(unregister_poweroff_handler); + +/** + * do_kernel_poweroff - Execute kernel poweroff handler call chain + * + * Calls functions registered with register_poweroff_handler. + * + * Expected to be called from machine_poweroff as last step of the poweroff + * sequence. + * + * Powers off the system immediately if a poweroff handler function + * has been registered. Otherwise does nothing. + */ +void do_kernel_poweroff(void) +{ + atomic_notifier_call_chain(&poweroff_handler_list, 0, NULL); +} + +/* + * Notifier list for kernel code which wants to be called * to restart the system. */ static ATOMIC_NOTIFIER_HEAD(restart_handler_list);