From patchwork Thu Oct 31 06:27:09 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Domenico Andreoli X-Patchwork-Id: 3118981 Return-Path: X-Original-To: patchwork-linux-arm@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 4F7A4BF924 for ; Thu, 31 Oct 2013 06:34:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D85C6203DF for ; Thu, 31 Oct 2013 06:34:19 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 43F98203EC for ; Thu, 31 Oct 2013 06:34:15 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vblnk-0005Vw-Fh; Thu, 31 Oct 2013 06:32:18 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VblnB-0008KU-8h; Thu, 31 Oct 2013 06:31:41 +0000 Received: from mail-ea0-x235.google.com ([2a00:1450:4013:c01::235]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Vbllz-0008Bu-T0 for linux-arm-kernel@lists.infradead.org; Thu, 31 Oct 2013 06:30:39 +0000 Received: by mail-ea0-f181.google.com with SMTP id d10so1148478eaj.12 for ; Wed, 30 Oct 2013 23:30:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:user-agent:date:from:to:cc:subject:references :content-disposition; bh=EsSxRLuw0t/XSaOlIrrdSHhX78NcPfuRGItwkkbz0GM=; b=wWkN9CFclKrLX1cqpdJDTX8oRobYvanp2Axr+KFKj6KCD16WBsWXbr55LC7cCbe8MB DaQGJCnBBx+vmDVXPEDFvITdiD7lNpQPEGTRTiAgaKLH78RK6RmNxgXHg3kd39yPBSU9 mD6gn0BLGVGHmyO0i9SfOQ19LmvyrEanq/epqxdVvjJlnwBoae5zHBiPAR2R7SeVfpZ0 1RRl0h2KexT+25JsGpVuHhOHzTaLcGVTATkT/81j+bGQytc7fz65/p6Ai+IBrEzF8Zkj Lcn/MD5BXxs9vLM4gMZgc2BDK4F3gMLxJg69jSyUe2Mp92DSXdr0p+w/Y7dLIHRuAWOH TbBg== X-Received: by 10.14.219.198 with SMTP id m46mr1380699eep.41.1383201003342; Wed, 30 Oct 2013 23:30:03 -0700 (PDT) Received: from shock.dandreoli.com (j115181.upc-j.chello.nl. [24.132.115.181]) by mx.google.com with ESMTPSA id k7sm4387844eeg.13.2013.10.30.23.30.00 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Oct 2013 23:30:01 -0700 (PDT) Received: by shock.dandreoli.com (Postfix, from userid 1000) id 86D13340133; Thu, 31 Oct 2013 07:29:58 +0100 (CET) Message-Id: <20131031062958.274180101@linux.com> User-Agent: quilt/0.60-1 Date: Thu, 31 Oct 2013 07:27:09 +0100 From: Domenico Andreoli To: linux-arch@vger.kernel.org Subject: [PATCH 01/11] machine-reset: platform generic handling References: <20131031062708.520968323@linux.com> Content-Disposition: inline; filename=machine-reset-handling.patch X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131031_023028_276276_38B9ACBA X-CRM114-Status: GOOD ( 20.81 ) X-Spam-Score: -1.9 (-) Cc: Russell King , Arnd Bergmann , Catalin Marinas , Will Deacon , Ralf Baechle , Domenico Andreoli , linux-mips@lvger.kernel.org, Olof Johansson , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,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 From: Domenico Andreoli Code is not commented but it's really simple. The bulk is in set_machine_reset(), the static data is hidden in get_descr(). The rest is just a straightforward consequence with the intent to keep it simple. Cc: Russell King Cc: Arnd Bergmann Cc: Olof Johansson Cc: Catalin Marinas Cc: Will Deacon Cc: Ralf Baechle Cc: linux-arch@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mips@lvger.kernel.org Signed-off-by: Domenico Andreoli --- include/linux/machine_reset.h | 79 +++++++++++++++++++++++++ kernel/Makefile | 1 + kernel/machine_reset.c | 131 ++++++++++++++++++++++++++++++++++++++++++ kernel/power/Kconfig | 4 + kernel/reboot.c | 3 + 5 files changed, 218 insertions(+) Index: b/include/linux/machine_reset.h =================================================================== --- /dev/null +++ b/include/linux/machine_reset.h @@ -0,0 +1,79 @@ +/* + * Machine reset hooks management + * + * Copyright (C) 2013 Domenico Andreoli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + +enum reset_func { + RESET_RESTART = 0, + RESET_HALT, + RESET_POWER_OFF_PREPARE, + RESET_POWER_OFF, + RESET_CRASH_POWER_OFF, + RESET_NR_FUNCS, +}; + +struct reset_hook { + union { + void (*restart)(void *dev, enum reboot_mode, const char *cmd); + void (*halt)(void *dev); + void (*power_off_prepare)(void *dev); + void (*power_off)(void *dev); + void (*crash_power_off)(void *dev); + void (*handler)(void *dev); + }; + void (*release)(void *dev); +}; + +static inline +void reset_hook_init(struct reset_hook *hook) +{ + hook->handler = NULL; + hook->release = NULL; +} + +#ifdef CONFIG_MACHINE_RESET + +void set_machine_reset(enum reset_func, const struct reset_hook *, void *dev); +void unset_machine_reset(enum reset_func, const struct reset_hook *); +int isset_machine_reset(enum reset_func, void *dev); + +void default_restart(enum reboot_mode, const char *cmd); +void default_halt(void); +void default_power_off_prepare(void); +void default_power_off(void); +void default_crash_power_off(void); + +#else /* CONFIG_MACHINE_RESET */ + +static inline +void set_machine_reset(enum reset_func func, + const struct reset_hook *hook, void *dev) +{ + if (hook->release) + hook->release(dev); +} + +static inline void unset_machine_reset(enum reset_func _f, + const struct reset_hook *_h) {} +static inline int isset_machine_reset(enum reset_func _f, void *_d) { return 0; } + +static inline void default_restart(enum reboot_mode _m, const char *_c) {} +static inline void default_halt(void) {} +static inline void default_power_off_prepare(void) {} +static inline void default_power_off(void) {} +static inline void default_crash_power_off(void) {} + +#endif /* CONFIG_MACHINE_RESET */ Index: b/kernel/Makefile =================================================================== --- a/kernel/Makefile +++ b/kernel/Makefile @@ -111,6 +111,7 @@ obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o +obj-$(CONFIG_MACHINE_RESET) += machine_reset.o $(obj)/configs.o: $(obj)/config_data.h Index: b/kernel/machine_reset.c =================================================================== --- /dev/null +++ b/kernel/machine_reset.c @@ -0,0 +1,131 @@ +/* + * Machine reset hooks management + * + * Copyright (C) 2013 Domenico Andreoli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + +struct reset_descr { + struct reset_hook hook; + void *dev; +}; +static DEFINE_SPINLOCK(descr_lock); + +static struct reset_descr *get_descr(enum reset_func func) +{ + static struct reset_descr descr[RESET_NR_FUNCS]; + + BUG_ON(func >= RESET_NR_FUNCS); + spin_lock(&descr_lock); + return &descr[func]; +} + +static void put_descr(struct reset_descr *descr) +{ + spin_unlock(&descr_lock); +} + +#define RESET_FUNC(_func, _member, _args...) \ +{ \ + struct reset_descr *descr = get_descr(_func); \ + typeof(descr->hook._member) member = descr->hook._member; \ + if (member) { \ + pr_debug("machine_reset: %s (%pf)\n", #_func, member); \ + member(descr->dev , ##_args); \ + } \ + put_descr(descr); \ + pr_emerg("machine_reset: %s: FAILED\n", #_func); \ + while (1); \ +} + +void default_restart(enum reboot_mode reboot_mode, const char *cmd) +{ + RESET_FUNC(RESET_RESTART, restart, reboot_mode, cmd); +} + +void default_halt(void) +{ + RESET_FUNC(RESET_HALT, halt); +} + +void default_power_off_prepare(void) +{ + RESET_FUNC(RESET_POWER_OFF_PREPARE, power_off_prepare); +} + +void default_power_off(void) +{ + RESET_FUNC(RESET_POWER_OFF, power_off); +} + +void default_crash_power_off(void) +{ + RESET_FUNC(RESET_CRASH_POWER_OFF, crash_power_off); +} + +void set_machine_reset(enum reset_func func, + const struct reset_hook *hook, void *new_dev) +{ + struct reset_descr *descr; + void (*new_handler)(void *) = hook ? hook->handler : NULL; + void (*new_release)(void *) = hook ? hook->release : NULL; + void (*old_release)(void *) = NULL; + void *old_dev; + + descr = get_descr(func); + old_release = descr->hook.release; + old_dev = descr->dev; + reset_hook_init(&descr->hook); + descr->hook.handler = new_handler; + descr->hook.release = new_release; + descr->dev = new_dev; + put_descr(descr); + + if (old_release) + old_release(old_dev); +} +EXPORT_SYMBOL_GPL(set_machine_reset); + +void unset_machine_reset(enum reset_func func, const struct reset_hook *hook) +{ + struct reset_descr *descr; + void (*old_release)(void *) = NULL; + void *old_dev; + + BUG_ON(!hook || !hook->handler); + + descr = get_descr(func); + if (descr->hook.handler == hook->handler) { + old_release = descr->hook.release; + old_dev = descr->dev; + reset_hook_init(&descr->hook); + } + put_descr(descr); + + if (old_release) + old_release(old_dev); +} +EXPORT_SYMBOL_GPL(unset_machine_reset); + +int isset_machine_reset(enum reset_func func, void *dev) +{ + struct reset_descr *descr = get_descr(func); + int ret = descr->hook.handler && (!dev || descr->dev == dev); + put_descr(descr); + return ret; +} +EXPORT_SYMBOL_GPL(isset_machine_reset); Index: b/kernel/power/Kconfig =================================================================== --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -293,3 +293,7 @@ config PM_GENERIC_DOMAINS_RUNTIME config CPU_PM bool depends on SUSPEND || CPU_IDLE + +config MACHINE_RESET + bool + default n Index: b/kernel/reboot.c =================================================================== --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -178,6 +179,8 @@ void kernel_power_off(void) kernel_shutdown_prepare(SYSTEM_POWER_OFF); if (pm_power_off_prepare) pm_power_off_prepare(); + else + default_power_off_prepare(); migrate_to_reboot_cpu(); syscore_shutdown(); pr_emerg("Power down\n");