mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage"
@ 2015-06-23 12:57 Juergen Borleis
  2015-06-23 12:58 ` [PATCH 1/5] Reset reason: add a scope value to the reset reason feature Juergen Borleis
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Juergen Borleis @ 2015-06-23 12:57 UTC (permalink / raw)
  To: barebox

This is V2 of this patch set. Changelog:

- some functions are renamed to better reflect their meaning
  ("*_register_handler" instead of "*_add_scope")
- collect most of the new features in one sourcefile, due to the fact they
  manage system reset and share some data
- clean up and remove some files, because they do not provide a function
  anymore (due to the removement of reset_cpu()).
- the reset cause detection and restart feature is now always part of barebox

Currently the architectures in barebox using a fixed approach to restart the
machine: they just provide a cpu_reset() function and are done. Every
architecture then does what the developer has selected in order to reset the
CPU, the SoC or the whole machine.

This approach is nice and simple but can fail. For example on a machine where
some kind of power management changes power supply voltages in order to save
power. Everything works with reduced clock speeds and voltages. It works until
a warm start is triggered and the SoC and it clocks are reset to their POR
defaults - but not the external power supply. In this case a restart feature
is required with a wider scope - which resets the power supplies back to their
POR values.

To honor the scope of a restart feature is the intention of this patch series.
And while a machine restart needs such a scope the use of a watchdog needs
such a scope as well. And at the end of this topic, the detection of the reset
cause also.

BTW: everything works in a reliable manner only, if the kernel honors these
scopes as well.

Patch 2/5 removes the reset_cpu() function barebox wide and replaces it by
registering an architecture dependend restart feature including a scope.
Patch 5/5 adds a new driver to handle the DA9055 PMIC which can act as a reset
cause detection, a watchdog and a restart unit. It is an example for a unit
which has a machine wide scope for all of these three featured.

Comments are welcome
Juergen


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/5] Reset reason: add a scope value to the reset reason feature
  2015-06-23 12:57 [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
@ 2015-06-23 12:58 ` Juergen Borleis
  2015-06-24  6:32   ` Sascha Hauer
  2015-06-23 12:58 ` [PATCH 2/5] System restart: add a scope value to the system restart feature Juergen Borleis
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Juergen Borleis @ 2015-06-23 12:58 UTC (permalink / raw)
  To: barebox

Some systems do have more than one source to detect the reason of a reset.
In this case it depends on the initialization order which reason will be
reported to barebox. To avoid this race, this change adds a scope to the
function call to always accept settings with a wider scope and ignore
all settings with a limited scope.

This change is required to support systems where one reset reason source
is more reliable than other sources. Examples are all i.MX SoCs with
an internal reset reason detector and an external PMIC which has the same
capabilities. For these systems the external PMIC provides the correct
reset cause while the internal unit flags a POR only all the time. In order
to support one binary for more than one machine we cannot just disable the
internal reset reason detector, so we need this scope mechanism.

Assumption in this change is, the reset cause sources with a wider scope are
always reporting the correct reason and not vice versa.

Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 Documentation/user/reset-reason.rst   | 30 ++++++++++++++
 Documentation/user/system-reset.rst   |  3 +-
 arch/arm/mach-imx/imx1.c              |  8 ++--
 arch/arm/mach-omap/am33xx_generic.c   | 14 +++----
 arch/arm/mach-pxa/pxa2xx.c            | 12 +++---
 arch/arm/mach-pxa/pxa3xx.c            | 12 +++---
 arch/arm/mach-samsung/reset_source.c  |  8 ++--
 arch/arm/mach-tegra/tegra20-pmc.c     | 14 +++----
 common/Kconfig                        |  8 ----
 common/Makefile                       |  2 +-
 common/reset_source.c                 | 56 ---------------------------
 common/restart.c                      | 73 +++++++++++++++++++++++++++++++++++
 drivers/watchdog/im28wd.c             | 12 +++---
 drivers/watchdog/imxwd.c              |  8 ++--
 include/{reset_source.h => restart.h} | 29 +++++++-------
 15 files changed, 164 insertions(+), 125 deletions(-)
 delete mode 100644 common/reset_source.c
 create mode 100644 common/restart.c
 rename include/{reset_source.h => restart.h} (71%)

diff --git a/Documentation/user/reset-reason.rst b/Documentation/user/reset-reason.rst
index a4872fa..525ade2 100644
--- a/Documentation/user/reset-reason.rst
+++ b/Documentation/user/reset-reason.rst
@@ -3,6 +3,9 @@
 Reset Reason
 ------------
 
+Using the Reset Reason
+~~~~~~~~~~~~~~~~~~~~~~
+
 To handle a device in a secure and safty manner many applications are using
 a watchdog or other ways to reset a system to bring it back into life if it
 hangs or crashes somehow.
@@ -45,3 +48,30 @@ The following values can help to detect the reason why the bootloader runs:
 It depends on your board/SoC and its features if the hardware is able to detect
 these reset reasons. Most of the time only ``POR`` and ``RST`` are supported
 but often ``WDG`` as well.
+
+.. _reset_reason_scope:
+
+Scope of Reset Reason
+~~~~~~~~~~~~~~~~~~~~~
+
+Some machines can detect the reset reason via different devices, for example
+via a SoC internal devices and an externally attached device. Both can provide
+the correct reason - or not. If their reset reason point of view differ, you
+need a ``scope`` to decide what reason is the correct one. Barebox provides
+the reset reason scope via the global variable ``system.reset.scope`` and
+the following values:
+
+* ``unknown``: the software can't define the scope of the reset reason.
+* ``cpu``: the inner core CPU only point of view.
+* ``soc``: the full SoC point of view.
+* ``machine``: the full machine point of view
+
+The scopes are rated: lowest rate is ``unknown`` and ``cpu``. The highest
+rate has the ``machine`` point of view. The ``soc`` point of view in inbetween.
+
+Why can the reset reason differ due to different scopes? Think about a SoC which
+is powered by a PMIC: the reset reason detection inside the SoC has the ``soc``
+scope, the PMIC's reset reason detection has the ``machine`` scope. In this case
+the ``soc`` scope reset reason is always ``POR``, while the ``machine`` scope
+reset reason is ``POR`` only on a real POR, ``RST`` due to an user
+intervention and ``WDG`` because the system has failed somehow.
diff --git a/Documentation/user/system-reset.rst b/Documentation/user/system-reset.rst
index e76e3a2..e902026 100644
--- a/Documentation/user/system-reset.rst
+++ b/Documentation/user/system-reset.rst
@@ -61,4 +61,5 @@ wide reset, like the POR is.
 Drawback of the PMIC solution is, you can't use the SoC's internal mechanisms to
 detect the :ref:`reset_reason` anymore. From the SoC point of view it is always
 a POR when the PMIC handles the system reset. If you are in luck the PMIC
-instead can provide this information if you depend on it.
+instead can provide this information if you depend on it. Refer
+:ref:`reset_reason_scope` for further information.
diff --git a/arch/arm/mach-imx/imx1.c b/arch/arm/mach-imx/imx1.c
index 51bdcbf..a3759df 100644
--- a/arch/arm/mach-imx/imx1.c
+++ b/arch/arm/mach-imx/imx1.c
@@ -18,7 +18,7 @@
 #include <mach/weim.h>
 #include <mach/iomux-v1.h>
 #include <mach/generic.h>
-#include <reset_source.h>
+#include <restart.h>
 
 #define MX1_RSR MX1_SCM_BASE_ADDR
 #define RSR_EXR	(1 << 0)
@@ -30,13 +30,13 @@ static void imx1_detect_reset_source(void)
 
 	switch (val) {
 	case RSR_EXR:
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 		return;
 	case RSR_WDR:
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 		return;
 	case 0:
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 		return;
 	default:
 		/* else keep the default 'unknown' state */
diff --git a/arch/arm/mach-omap/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c
index 7ce32f0..8ac1290 100644
--- a/arch/arm/mach-omap/am33xx_generic.c
+++ b/arch/arm/mach-omap/am33xx_generic.c
@@ -26,7 +26,7 @@
 #include <mach/sys_info.h>
 #include <mach/am33xx-generic.h>
 #include <mach/gpmc.h>
-#include <reset_source.h>
+#include <restart.h>
 
 void __noreturn am33xx_reset_cpu(unsigned long addr)
 {
@@ -167,23 +167,23 @@ static void am33xx_detect_reset_reason(void)
 
 	switch (val) {
 	case (1 << 9):
-		reset_source_set(RESET_JTAG);
+		reset_source_set(RESET_JTAG, FEATURE_SCOPE_SOC);
 		break;
 	case (1 << 5):
-		reset_source_set(RESET_EXT);
+		reset_source_set(RESET_EXT, FEATURE_SCOPE_SOC);
 		break;
 	case (1 << 4):
 	case (1 << 3):
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 		break;
 	case (1 << 1):
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 		break;
 	case (1 << 0):
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 		break;
 	default:
-		reset_source_set(RESET_UKWN);
+		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
 		break;
 	}
 }
diff --git a/arch/arm/mach-pxa/pxa2xx.c b/arch/arm/mach-pxa/pxa2xx.c
index b712b38..973e394 100644
--- a/arch/arm/mach-pxa/pxa2xx.c
+++ b/arch/arm/mach-pxa/pxa2xx.c
@@ -14,7 +14,7 @@
 
 #include <common.h>
 #include <init.h>
-#include <reset_source.h>
+#include <restart.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 
@@ -28,15 +28,15 @@ static int pxa_detect_reset_source(void)
 	 * Order is important, as many bits can be set together
 	 */
 	if (reg & RCSR_GPR)
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 	else if (reg & RCSR_WDR)
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 	else if (reg & RCSR_HWR)
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 	else if (reg & RCSR_SMR)
-		reset_source_set(RESET_WKE);
+		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
 	else
-		reset_source_set(RESET_UKWN);
+		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
 
 	return 0;
 }
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 86ca63b..e273996 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -14,7 +14,7 @@
 
 #include <common.h>
 #include <init.h>
-#include <reset_source.h>
+#include <restart.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 
@@ -28,15 +28,15 @@ static int pxa_detect_reset_source(void)
 	 * Order is important, as many bits can be set together
 	 */
 	if (reg & ARSR_GPR)
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 	else if (reg & ARSR_WDT)
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 	else if (reg & ARSR_HWR)
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 	else if (reg & ARSR_LPMR)
-		reset_source_set(RESET_WKE);
+		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
 	else
-		reset_source_set(RESET_UKWN);
+		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
 
 	return 0;
 }
diff --git a/arch/arm/mach-samsung/reset_source.c b/arch/arm/mach-samsung/reset_source.c
index c1365b2..e122909 100644
--- a/arch/arm/mach-samsung/reset_source.c
+++ b/arch/arm/mach-samsung/reset_source.c
@@ -15,7 +15,7 @@
 #include <common.h>
 #include <init.h>
 #include <io.h>
-#include <reset_source.h>
+#include <restart.h>
 #include <mach/s3c-iomap.h>
 
 /* S3C2440 relevant */
@@ -29,21 +29,21 @@ static int s3c_detect_reset_source(void)
 	u32 reg = readl(S3C_GPIO_BASE + S3C2440_GSTATUS2);
 
 	if (reg & S3C2440_GSTATUS2_PWRST) {
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 		writel(S3C2440_GSTATUS2_PWRST,
 					S3C_GPIO_BASE + S3C2440_GSTATUS2);
 		return 0;
 	}
 
 	if (reg & S3C2440_GSTATUS2_SLEEPRST) {
-		reset_source_set(RESET_WKE);
+		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
 		writel(S3C2440_GSTATUS2_SLEEPRST,
 					S3C_GPIO_BASE + S3C2440_GSTATUS2);
 		return 0;
 	}
 
 	if (reg & S3C2440_GSTATUS2_WDRST) {
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 		writel(S3C2440_GSTATUS2_WDRST,
 					S3C_GPIO_BASE + S3C2440_GSTATUS2);
 		return 0;
diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c
index eaa5ac7..6493eea 100644
--- a/arch/arm/mach-tegra/tegra20-pmc.c
+++ b/arch/arm/mach-tegra/tegra20-pmc.c
@@ -28,7 +28,7 @@
 #include <linux/reset.h>
 #include <mach/lowlevel.h>
 #include <mach/tegra-powergate.h>
-#include <reset_source.h>
+#include <restart.h>
 
 #include <mach/tegra20-pmc.h>
 
@@ -180,22 +180,22 @@ static void tegra20_pmc_detect_reset_cause(void)
 	switch ((reg & PMC_RST_STATUS_RST_SRC_MASK) >>
 	         PMC_RST_STATUS_RST_SRC_SHIFT) {
 	case PMC_RST_STATUS_RST_SRC_POR:
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 		break;
 	case PMC_RST_STATUS_RST_SRC_WATCHDOG:
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 		break;
 	case PMC_RST_STATUS_RST_SRC_LP0:
-		reset_source_set(RESET_WKE);
+		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
 		break;
 	case PMC_RST_STATUS_RST_SRC_SW_MAIN:
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 		break;
 	case PMC_RST_STATUS_RST_SRC_SENSOR:
-		reset_source_set(RESET_THERM);
+		reset_source_set(RESET_THERM, FEATURE_SCOPE_SOC);
 		break;
 	default:
-		reset_source_set(RESET_UKWN);
+		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
 		break;
 	}
 }
diff --git a/common/Kconfig b/common/Kconfig
index 3dfb5ac..f241482 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -716,14 +716,6 @@ config STATE
 	select OFTREE
 	select PARAMETER
 
-config RESET_SOURCE
-	bool "detect Reset cause"
-	depends on GLOBALVAR
-	help
-	  Provide a global variable at runtine which reflects the possible cause
-	  of the reset and why the bootloader is currently running. It can be
-	  useful for any kind of system recovery or repair.
-
 endmenu
 
 menu "Debugging"
diff --git a/common/Makefile b/common/Makefile
index 2738238..16e6690 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -8,6 +8,7 @@ obj-y				+= misc.o
 obj-y				+= memsize.o
 obj-y				+= resource.o
 obj-y				+= bootsource.o
+obj-y				+= restart.o
 obj-$(CONFIG_AUTO_COMPLETE)	+= complete.o
 obj-$(CONFIG_BANNER)		+= version.o
 obj-$(CONFIG_BAREBOX_UPDATE)	+= bbu.o
@@ -40,7 +41,6 @@ obj-$(CONFIG_OFTREE)		+= oftree.o
 obj-$(CONFIG_PARTITION_DISK)	+= partitions.o partitions/
 obj-$(CONFIG_PASSWORD)		+= password.o
 obj-$(CONFIG_POLLER)		+= poller.o
-obj-$(CONFIG_RESET_SOURCE)	+= reset_source.o
 obj-$(CONFIG_SHELL_HUSH)	+= hush.o
 obj-$(CONFIG_SHELL_SIMPLE)	+= parser.o
 obj-$(CONFIG_STATE)		+= state.o
diff --git a/common/reset_source.c b/common/reset_source.c
deleted file mode 100644
index 80002a9..0000000
--- a/common/reset_source.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * (C) Copyright 2012 Juergen Beisert - <kernel@pengutronix.de>
- *
- * 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 <common.h>
-#include <init.h>
-#include <environment.h>
-#include <globalvar.h>
-#include <reset_source.h>
-
-static const char * const reset_src_names[] = {
-	[RESET_UKWN] = "unknown",
-	[RESET_POR] = "POR",
-	[RESET_RST] = "RST",
-	[RESET_WDG] = "WDG",
-	[RESET_WKE] = "WKE",
-	[RESET_JTAG] = "JTAG",
-	[RESET_THERM] = "THERM",
-	[RESET_EXT] = "EXT",
-};
-
-static enum reset_src_type reset_source;
-
-enum reset_src_type reset_source_get(void)
-{
-	return reset_source;
-}
-EXPORT_SYMBOL(reset_source_get);
-
-void reset_source_set(enum reset_src_type st)
-{
-	reset_source = st;
-
-	globalvar_add_simple("system.reset", reset_src_names[reset_source]);
-}
-EXPORT_SYMBOL(reset_source_set);
-
-/* ensure this runs after the 'global' device is already registerd */
-static int reset_source_init(void)
-{
-	reset_source_set(reset_source);
-
-	return 0;
-}
-
-coredevice_initcall(reset_source_init);
diff --git a/common/restart.c b/common/restart.c
new file mode 100644
index 0000000..f73a9da
--- /dev/null
+++ b/common/restart.c
@@ -0,0 +1,73 @@
+/*
+ * (C) Copyright 2015 Juergen Borleis - <kernel@pengutronix.de>
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <restart.h>
+#include <globalvar.h>
+
+static const char * const scope_names[] = {
+	[FEATURE_SCOPE_UNKNOWN] = "unknown",
+	[FEATURE_SCOPE_CPU] = "cpu",
+	[FEATURE_SCOPE_SOC] = "soc",
+	[FEATURE_SCOPE_MACHINE] = "machine",
+};
+
+static const char * const reset_src_names[] = {
+	[RESET_UKWN] = "unknown",
+	[RESET_POR] = "POR",
+	[RESET_RST] = "RST",
+	[RESET_WDG] = "WDG",
+	[RESET_WKE] = "WKE",
+	[RESET_JTAG] = "JTAG",
+	[RESET_THERM] = "THERM",
+	[RESET_EXT] = "EXT",
+};
+
+/* handle reset cause detection feature */
+
+static int reset_source;
+static int reset_source_scope;
+
+enum reset_src_type reset_source_get(void)
+{
+	return reset_source;
+}
+EXPORT_SYMBOL(reset_source_get);
+
+static void reset_source_update_global_info(void)
+{
+	globalvar_add_simple_enum("system.reset", &reset_source, reset_src_names,
+					ARRAY_SIZE(reset_src_names));
+	globalvar_add_simple_enum("system.reset.scope", &reset_source_scope,
+					scope_names, ARRAY_SIZE(scope_names));
+}
+
+void reset_source_set(enum reset_src_type st, enum f_scope scope)
+{
+	if ((int)scope <= reset_source_scope)
+		return; /* just ignore this setting */
+
+	reset_source = (int)st;
+	reset_source_scope = (int)scope;
+	reset_source_update_global_info();
+}
+EXPORT_SYMBOL(reset_source_set);
+
+static int reset_feature_init(void)
+{
+	reset_source_update_global_info();
+	return 0;
+}
+coredevice_initcall(reset_feature_init);
diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c
index a9093a7..c824a25 100644
--- a/drivers/watchdog/im28wd.c
+++ b/drivers/watchdog/im28wd.c
@@ -21,7 +21,7 @@
 #include <errno.h>
 #include <malloc.h>
 #include <watchdog.h>
-#include <reset_source.h>
+#include <restart.h>
 #include <linux/err.h>
 
 #define MXS_RTC_CTRL 0x0
@@ -164,27 +164,27 @@ static void __maybe_unused imx28_detect_reset_source(const struct imx28_wd *p)
 		if (reg & MXS_RTC_PERSISTENT0_ALARM_WAKE) {
 			writel(MXS_RTC_PERSISTENT0_ALARM_WAKE,
 				p->regs + MXS_RTC_PERSISTENT0 + MXS_RTC_CLR_ADDR);
-			reset_source_set(RESET_WKE);
+			reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
 			return;
 		}
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 		return;
 	}
 	if (reg & MXS_RTC_PERSISTENT0_THM_RST) {
 		writel(MXS_RTC_PERSISTENT0_THM_RST,
 			p->regs + MXS_RTC_PERSISTENT0 + MXS_RTC_CLR_ADDR);
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 		return;
 	}
 	reg = readl(p->regs + MXS_RTC_PERSISTENT1);
 	if (reg & MXS_RTC_PERSISTENT1_FORCE_UPDATER) {
 		writel(MXS_RTC_PERSISTENT1_FORCE_UPDATER,
 			p->regs + MXS_RTC_PERSISTENT1 + MXS_RTC_CLR_ADDR);
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 		return;
 	}
 
-	reset_source_set(RESET_RST);
+	reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 }
 
 static int imx28_wd_probe(struct device_d *dev)
diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
index 5ffbac7..f3decae 100644
--- a/drivers/watchdog/imxwd.c
+++ b/drivers/watchdog/imxwd.c
@@ -19,7 +19,7 @@
 #include <errno.h>
 #include <malloc.h>
 #include <watchdog.h>
-#include <reset_source.h>
+#include <restart.h>
 
 struct imx_wd;
 
@@ -138,17 +138,17 @@ static void imx_watchdog_detect_reset_source(struct imx_wd *priv)
 	u16 val = readw(priv->base + IMX21_WDOG_WSTR);
 
 	if (val & WSTR_COLDSTART) {
-		reset_source_set(RESET_POR);
+		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
 		return;
 	}
 
 	if (val & (WSTR_HARDRESET | WSTR_WARMSTART)) {
-		reset_source_set(RESET_RST);
+		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
 		return;
 	}
 
 	if (val & WSTR_WDOG) {
-		reset_source_set(RESET_WDG);
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
 		return;
 	}
 
diff --git a/include/reset_source.h b/include/restart.h
similarity index 71%
rename from include/reset_source.h
rename to include/restart.h
index 367f93b..4215760 100644
--- a/include/reset_source.h
+++ b/include/restart.h
@@ -10,8 +10,18 @@
  * GNU General Public License for more details.
  */
 
-#ifndef __INCLUDE_RESET_SOURCE_H
-# define __INCLUDE_RESET_SOURCE_H
+#ifndef __INCLUDE_SYSTEM_RESTART_H
+# define __INCLUDE_SYSTEM_RESTART_H
+
+/* define a scope a specific hardware feature can cope with */
+enum f_scope {
+	FEATURE_SCOPE_UNKNOWN,
+	FEATURE_SCOPE_CPU,
+	FEATURE_SCOPE_SOC,
+	FEATURE_SCOPE_MACHINE,
+};
+
+/* reset cause detection feature */
 
 enum reset_src_type {
 	RESET_UKWN,	/* maybe the SoC cannot detect the reset source */
@@ -24,18 +34,7 @@ enum reset_src_type {
 	RESET_EXT,	/* External reset through device pin */
 };
 
-#ifdef CONFIG_RESET_SOURCE
-void reset_source_set(enum reset_src_type);
+void reset_source_set(enum reset_src_type, enum f_scope);
 enum reset_src_type reset_source_get(void);
-#else
-static inline void reset_source_set(enum reset_src_type unused)
-{
-}
-
-static inline enum reset_src_type reset_source_get(void)
-{
-	return RESET_UKWN;
-}
-#endif
 
-#endif /* __INCLUDE_RESET_SOURCE_H */
+#endif /* __INCLUDE_SYSTEM_RESTART_H */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/5] System restart: add a scope value to the system restart feature
  2015-06-23 12:57 [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
  2015-06-23 12:58 ` [PATCH 1/5] Reset reason: add a scope value to the reset reason feature Juergen Borleis
@ 2015-06-23 12:58 ` Juergen Borleis
  2015-06-24  6:42   ` Sascha Hauer
  2015-06-23 12:58 ` [PATCH 3/5] Watchdog: add a scope value to the watchdog feature Juergen Borleis
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Juergen Borleis @ 2015-06-23 12:58 UTC (permalink / raw)
  To: barebox

Some systems have more than one feature to restart it. Maybe these restarts
features are all equal or it is very important which restart feauture is used
to restart the system in a reliable manner. For example if external
devices must be reset in conjunction with the SoC some SoC's internal
restart features cannot be used. Then an external restart feature must
be forced instead by using the restart feature with the wider scope.

Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 Documentation/user/system-reset.rst              | 41 ++++++++++++++++++
 arch/arm/lib/bootm.c                             |  7 +--
 arch/arm/mach-at91/at91rm9200_time.c             | 12 ++++--
 arch/arm/mach-bcm2835/core.c                     | 21 ++++-----
 arch/arm/mach-clps711x/reset.c                   | 10 ++++-
 arch/arm/mach-davinci/time.c                     | 12 ++++--
 arch/arm/mach-digic/core.c                       | 25 -----------
 arch/arm/mach-ep93xx/clocksource.c               | 17 +++++---
 arch/arm/mach-highbank/reset.c                   | 12 +++++-
 arch/arm/mach-mvebu/armada-370-xp.c              |  9 ++--
 arch/arm/mach-mvebu/common.c                     | 13 ------
 arch/arm/mach-mvebu/dove.c                       |  9 ++--
 arch/arm/mach-mvebu/include/mach/common.h        |  1 -
 arch/arm/mach-mvebu/kirkwood.c                   |  9 ++--
 arch/arm/mach-mxs/soc-imx23.c                    |  8 ++--
 arch/arm/mach-mxs/soc-imx28.c                    | 13 ++++--
 arch/arm/mach-netx/generic.c                     | 11 ++++-
 arch/arm/mach-nomadik/reset.c                    | 13 ++++--
 arch/arm/mach-omap/am33xx_generic.c              |  4 +-
 arch/arm/mach-omap/include/mach/am33xx-generic.h |  2 +-
 arch/arm/mach-omap/include/mach/omap3-generic.h  |  2 +-
 arch/arm/mach-omap/include/mach/omap4-generic.h  |  2 +-
 arch/arm/mach-omap/omap3_generic.c               |  5 +--
 arch/arm/mach-omap/omap4_generic.c               |  4 +-
 arch/arm/mach-omap/omap_generic.c                | 12 +++---
 arch/arm/mach-pxa/common.c                       | 12 +++++-
 arch/arm/mach-rockchip/core.c                    | 14 ++++--
 arch/arm/mach-samsung/generic.c                  | 13 ++++--
 arch/arm/mach-socfpga/reset-manager.c            | 12 +++++-
 arch/arm/mach-tegra/tegra20-pmc.c                |  6 +--
 arch/arm/mach-uemd/reset.c                       | 24 -----------
 arch/arm/mach-versatile/core.c                   |  7 +--
 arch/arm/mach-vexpress/reset.c                   | 13 ++++--
 arch/arm/mach-zynq/zynq.c                        | 12 ++++--
 arch/blackfin/lib/cpu.c                          | 11 ++++-
 arch/efi/efi/efi.c                               | 11 ++++-
 arch/mips/mach-ar231x/ar231x_reset.c             |  8 ++--
 arch/mips/mach-ath79/reset.c                     | 13 ++++--
 arch/mips/mach-bcm47xx/reset.c                   | 14 ++++--
 arch/mips/mach-loongson/loongson1_reset.c        | 13 ++++--
 arch/mips/mach-malta/reset.c                     | 14 ++++--
 arch/nios2/cpu/cpu.c                             | 12 +++++-
 arch/openrisc/cpu/cpu.c                          | 11 ++++-
 arch/ppc/mach-mpc5xxx/cpu.c                      | 11 ++++-
 arch/ppc/mach-mpc85xx/cpu.c                      | 12 ++++--
 arch/sandbox/os/common.c                         | 10 ++++-
 arch/x86/mach-i386/reset.c                       | 30 -------------
 commands/reset.c                                 |  3 +-
 common/misc.c                                    |  3 +-
 common/restart.c                                 | 55 ++++++++++++++++++++++++
 drivers/usb/gadget/f_fastboot.c                  |  3 +-
 drivers/watchdog/imxwd.c                         | 21 ++++-----
 drivers/watchdog/jz4740.c                        | 33 ++++++--------
 include/common.h                                 |  1 -
 include/restart.h                                |  6 +++
 55 files changed, 432 insertions(+), 250 deletions(-)
 delete mode 100644 arch/arm/mach-digic/core.c
 delete mode 100644 arch/arm/mach-uemd/reset.c
 delete mode 100644 arch/x86/mach-i386/reset.c

diff --git a/Documentation/user/system-reset.rst b/Documentation/user/system-reset.rst
index e902026..6770371 100644
--- a/Documentation/user/system-reset.rst
+++ b/Documentation/user/system-reset.rst
@@ -3,6 +3,11 @@
 System Restart
 --------------
 
+.. _system_reset_pitfalls:
+
+Common Pitfalls
+~~~~~~~~~~~~~~~
+
 When running the reset command barebox restarts the SoC somehow. Restart can
 be done in software, but a more reliable way is to use a hard reset line, which
 really resets the whole machine.
@@ -63,3 +68,39 @@ detect the :ref:`reset_reason` anymore. From the SoC point of view it is always
 a POR when the PMIC handles the system reset. If you are in luck the PMIC
 instead can provide this information if you depend on it. Refer
 :ref:`reset_reason_scope` for further information.
+
+Handling the system restart from the developers point of view
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes more than one system restart feature is available on a machine and
+due to 'some reasons' all these unit's drivers must be enabled at run-time
+(maybe they are MFDs (e.g. multi function devices) or you want to run one
+binary barebox on more than one machine). In such a case more than one driver
+registers its system reset feature at run-time. So a mechanism is required
+in order to let barebox selects the 'correct' one to trigger a system restart.
+
+Barebox can handle and use one system restart feature only. If the available
+system restart features are equivalent it doesn't matter which one barebox
+selects to trigger a system restart. But if your machine depends on a specific
+system restart feature you must ensure it will be used all the time to get a
+reliable system restart.
+
+To handle this, registering system restart features are handled by their scope.
+Due to the listed issues in :ref:`system_reset_pitfalls` all the (mostly) built-in
+watchdog units will register their system restart feature with a limited scope.
+And will still be used by barebox to restart the system if no alternative is
+available.
+If your machine has special requirements to restart the system and a more reliable
+system restart feature is on hand it must register its system restart feature
+with a wider scope. Barebox will then prefer the wider scope feature to restart
+the system.
+
+Here the list of defined scopes (defined in file ``include/restart.h``):
+
+* ``FEATURE_SCOPE_UNKNOWN``: last resort to restart a machine and might be used
+  as a fall-back only.
+* ``FEATURE_SCOPE_CPU``: this restart feature is able to restart the core CPU only.
+* ``FEATURE_SCOPE_SOC``: this restart feature is able to restart the whole SoC,
+  including the core CPU.
+* ``FEATURE_SCOPE_MACHINE``: this restart feature is able to restart the whole machine,
+  including the SoC and the core CPU.
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 8327c3f..7bb9b43 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -16,6 +16,7 @@
 #include <libbb.h>
 #include <magicvar.h>
 #include <binfmt.h>
+#include <restart.h>
 
 #include <asm/byteorder.h>
 #include <asm/setup.h>
@@ -111,7 +112,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int
 
 	start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree);
 
-	reset_cpu(0);
+	restart_machine();
 
 	return -ERESTARTSYS;
 }
@@ -378,7 +379,7 @@ static int do_bootm_barebox(struct image_data *data)
 
 	start_linux(barebox, 0, 0, 0, data->oftree);
 
-	reset_cpu(0);
+	restart_machine();
 }
 
 static struct image_handler barebox_handler = {
@@ -518,7 +519,7 @@ static int do_bootm_aimage(struct image_data *data)
 
 		second();
 
-		reset_cpu(0);
+		restart_machine();
 	}
 
 	close(fd);
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index ae0172b..c017ad8 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -28,6 +28,7 @@
 #include <common.h>
 #include <init.h>
 #include <clock.h>
+#include <restart.h>
 #include <mach/hardware.h>
 #include <mach/at91_tc.h>
 #include <mach/at91_st.h>
@@ -77,7 +78,7 @@ core_initcall(clocksource_init);
 /*
  * Reset the cpu through the reset controller
  */
-void __noreturn reset_cpu (unsigned long ignored)
+static void __noreturn at91rm9200_restart_soc(struct device_d *dev)
 {
 	/*
 	 * Perform a hardware reset with the use of the Watchdog timer.
@@ -86,6 +87,11 @@ void __noreturn reset_cpu (unsigned long ignored)
 	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
 
 	/* Not reached */
-	while (1);
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(at91rm9200_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-bcm2835/core.c b/arch/arm/mach-bcm2835/core.c
index 5d08012..6f6ae8a 100644
--- a/arch/arm/mach-bcm2835/core.c
+++ b/arch/arm/mach-bcm2835/core.c
@@ -18,6 +18,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 
 #include <linux/clk.h>
 #include <linux/clkdev.h>
@@ -51,13 +52,6 @@ static int bcm2835_clk_init(void)
 }
 postcore_initcall(bcm2835_clk_init);
 
-static int bcm2835_dev_init(void)
-{
-	add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL);
-	return 0;
-}
-coredevice_initcall(bcm2835_dev_init);
-
 void bcm2835_register_uart(void)
 {
 	amba_apb_device_add(NULL, "uart0-pl011", 0, BCM2835_UART0_BASE, 4096, NULL, 0);
@@ -72,7 +66,7 @@ void bcm2835_add_device_sdram(u32 size)
 }
 #define RESET_TIMEOUT 10
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn bcm2835_restart_soc(struct device_d *dev)
 {
 	uint32_t rstc;
 
@@ -82,6 +76,13 @@ void __noreturn reset_cpu(unsigned long addr)
 	writel(PM_PASSWORD | RESET_TIMEOUT, PM_WDOG);
 	writel(PM_PASSWORD | rstc, PM_RSTC);
 
-	while (1);
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int bcm2835_dev_init(void)
+{
+	add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL);
+	restart_register_handler(bcm2835_restart_soc, NULL, FEATURE_SCOPE_SOC);
+	return 0;
+}
+coredevice_initcall(bcm2835_dev_init);
diff --git a/arch/arm/mach-clps711x/reset.c b/arch/arm/mach-clps711x/reset.c
index 67c9c8b..225ef15 100644
--- a/arch/arm/mach-clps711x/reset.c
+++ b/arch/arm/mach-clps711x/reset.c
@@ -8,8 +8,10 @@
  */
 
 #include <common.h>
+#include <init.h>
+#include <restart.h>
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn clps711x_restart_soc(struct device_d *dev)
 {
 	arch_shutdown();
 
@@ -17,3 +19,9 @@ void __noreturn reset_cpu(unsigned long addr)
 
 	hang();
 }
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(clps711x_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 60f0d19..8b53879 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -12,6 +12,7 @@
 #include <common.h>
 #include <io.h>
 #include <init.h>
+#include <restart.h>
 #include <clock.h>
 
 #include <mach/time.h>
@@ -164,7 +165,7 @@ static int clocksource_init(void)
 core_initcall(clocksource_init);
 
 /* reset board using watchdog timer */
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn davinci_restart_soc(struct device_d *dev)
 {
 	u32 tgcr, wdtcr;
 	void __iomem *base;
@@ -204,6 +205,11 @@ void __noreturn reset_cpu(ulong addr)
 	wdtcr = 0x00004000;
 	__raw_writel(wdtcr, base + WDTCR);
 
-	unreachable();
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(davinci_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-digic/core.c b/arch/arm/mach-digic/core.c
deleted file mode 100644
index b1caec0..0000000
--- a/arch/arm/mach-digic/core.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This file is part of barebox.
- * See file CREDITS for list of people who contributed to this project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * 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 <common.h>
-
-void __noreturn reset_cpu(unsigned long ignored)
-{
-	pr_err("%s: unimplemented\n", __func__);
-	hang();
-}
-EXPORT_SYMBOL(reset_cpu);
diff --git a/arch/arm/mach-ep93xx/clocksource.c b/arch/arm/mach-ep93xx/clocksource.c
index f396d0a..c811641 100644
--- a/arch/arm/mach-ep93xx/clocksource.c
+++ b/arch/arm/mach-ep93xx/clocksource.c
@@ -20,6 +20,7 @@
 #include <init.h>
 #include <clock.h>
 #include <io.h>
+#include <restart.h>
 #include <mach/ep93xx-regs.h>
 
 #define TIMER_CLKSEL		(1 << 3)
@@ -63,10 +64,8 @@ static int clocksource_init(void)
 
 core_initcall(clocksource_init);
 
-/*
- * Reset the cpu
- */
-void __noreturn reset_cpu(unsigned long addr)
+/* Reset the SoC */
+static void __noreturn ep92xx_restart_soc(struct device_d *dev)
 {
 	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
 	uint32_t value;
@@ -84,7 +83,11 @@ void __noreturn reset_cpu(unsigned long addr)
 	writel(value, &syscon->devicecfg);
 
 	/* Dying... */
-	while (1)
-		; /* noop */
+	hang();
+}
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(ep92xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
 }
-EXPORT_SYMBOL(reset_cpu);
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-highbank/reset.c b/arch/arm/mach-highbank/reset.c
index b9664e4..cff5cae 100644
--- a/arch/arm/mach-highbank/reset.c
+++ b/arch/arm/mach-highbank/reset.c
@@ -6,17 +6,25 @@
 
 #include <common.h>
 #include <io.h>
+#include <restart.h>
+#include <init.h>
 
 #include <mach/devices.h>
 #include <mach/sysregs.h>
 
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn highbank_restart_soc(struct device_d *dev)
 {
 	hingbank_set_pwr_hard_reset();
 	asm("	wfi");
 
-	while(1);
+	hang();
+}
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(highbank_restart_soc, NULL, FEATURE_SCOPE_SOC);
 }
+coredevice_initcall(restart_register_feature);
 
 void __noreturn poweroff()
 {
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index 2405629..0c52523 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -17,6 +17,7 @@
 #include <common.h>
 #include <init.h>
 #include <io.h>
+#include <restart.h>
 #include <of.h>
 #include <of_address.h>
 #include <asm/memory.h>
@@ -104,12 +105,12 @@ static int armada_370_xp_soc_id_fixup(void)
 	return 0;
 }
 
-static void __noreturn armada_370_xp_reset_cpu(unsigned long addr)
+static void __noreturn armada_370_xp_restart_soc(struct device_d *dev)
 {
 	writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x60);
 	writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x64);
-	while (1)
-		;
+
+	hang();
 }
 
 static int armada_xp_init_soc(struct device_node *root)
@@ -132,7 +133,7 @@ static int armada_370_xp_init_soc(struct device_node *root, void *context)
 	if (!of_machine_is_compatible("marvell,armada-370-xp"))
 		return 0;
 
-	mvebu_set_reset(armada_370_xp_reset_cpu);
+	restart_register_handler(armada_370_xp_restart_soc, NULL, FEATURE_SCOPE_SOC);
 
 	barebox_set_model("Marvell Armada 370/XP");
 	barebox_set_hostname("armada");
diff --git a/arch/arm/mach-mvebu/common.c b/arch/arm/mach-mvebu/common.c
index 7d28d9c..cb40d0c 100644
--- a/arch/arm/mach-mvebu/common.c
+++ b/arch/arm/mach-mvebu/common.c
@@ -123,16 +123,3 @@ int mvebu_set_memory(u64 phys_base, u64 phys_size)
 
 	return 0;
 }
-
-static __noreturn void (*mvebu_reset_cpu)(unsigned long addr);
-
-void __noreturn reset_cpu(unsigned long addr)
-{
-	mvebu_reset_cpu(addr);
-}
-EXPORT_SYMBOL(reset_cpu);
-
-void mvebu_set_reset(void __noreturn (*reset)(unsigned long addr))
-{
-	mvebu_reset_cpu = reset;
-}
diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c
index a7284fd..b727215 100644
--- a/arch/arm/mach-mvebu/dove.c
+++ b/arch/arm/mach-mvebu/dove.c
@@ -17,6 +17,7 @@
 #include <common.h>
 #include <init.h>
 #include <io.h>
+#include <restart.h>
 #include <asm/memory.h>
 #include <linux/mbus.h>
 #include <mach/dove-regs.h>
@@ -68,13 +69,13 @@ static inline void dove_memory_find(unsigned long *phys_base,
 	}
 }
 
-static void __noreturn dove_reset_cpu(unsigned long addr)
+static void __noreturn dove_restart_soc(struct device_d *dev)
 {
 	/* enable and assert RSTOUTn */
 	writel(SOFT_RESET_OUT_EN, DOVE_BRIDGE_BASE + BRIDGE_RSTOUT_MASK);
 	writel(SOFT_RESET_EN, DOVE_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET);
-	while (1)
-		;
+
+	hang();
 }
 
 static int dove_init_soc(struct device_node *root, void *context)
@@ -84,7 +85,7 @@ static int dove_init_soc(struct device_node *root, void *context)
 	if (!of_machine_is_compatible("marvell,dove"))
 		return 0;
 
-	mvebu_set_reset(dove_reset_cpu);
+	restart_register_handler(dove_restart_soc, NULL, FEATURE_SCOPE_SOC);
 
 	barebox_set_model("Marvell Dove");
 	barebox_set_hostname("dove");
diff --git a/arch/arm/mach-mvebu/include/mach/common.h b/arch/arm/mach-mvebu/include/mach/common.h
index 5ce33fd..602af8f 100644
--- a/arch/arm/mach-mvebu/include/mach/common.h
+++ b/arch/arm/mach-mvebu/include/mach/common.h
@@ -21,6 +21,5 @@
 #define MVEBU_REMAP_INT_REG_BASE	0xf1000000
 
 int mvebu_set_memory(u64 phys_base, u64 phys_size);
-void mvebu_set_reset(void __noreturn (*reset)(unsigned long addr));
 
 #endif
diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c
index 19c6f07..00e213f 100644
--- a/arch/arm/mach-mvebu/kirkwood.c
+++ b/arch/arm/mach-mvebu/kirkwood.c
@@ -16,6 +16,7 @@
 #include <common.h>
 #include <init.h>
 #include <io.h>
+#include <restart.h>
 #include <asm/memory.h>
 #include <linux/mbus.h>
 #include <mach/kirkwood-regs.h>
@@ -43,12 +44,12 @@ static inline void kirkwood_memory_find(unsigned long *phys_base,
 	}
 }
 
-static void __noreturn kirkwood_reset_cpu(unsigned long addr)
+static void __noreturn kirkwood_restart_soc(struct device_d *dev)
 {
 	writel(SOFT_RESET_OUT_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_RSTOUT_MASK);
 	writel(SOFT_RESET_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET);
-	for(;;)
-		;
+
+	hang();
 }
 
 static int kirkwood_init_soc(struct device_node *root, void *context)
@@ -58,7 +59,7 @@ static int kirkwood_init_soc(struct device_node *root, void *context)
 	if (!of_machine_is_compatible("marvell,kirkwood"))
 		return 0;
 
-	mvebu_set_reset(kirkwood_reset_cpu);
+	restart_register_handler(kirkwood_restart_soc, NULL, FEATURE_SCOPE_SOC);
 
 	barebox_set_model("Marvell Kirkwood");
 	barebox_set_hostname("kirkwood");
diff --git a/arch/arm/mach-mxs/soc-imx23.c b/arch/arm/mach-mxs/soc-imx23.c
index 339c577..fd8cf04 100644
--- a/arch/arm/mach-mxs/soc-imx23.c
+++ b/arch/arm/mach-mxs/soc-imx23.c
@@ -16,6 +16,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 #include <mach/imx23-regs.h>
 #include <io.h>
 
@@ -23,18 +24,16 @@
 # define HW_CLKCTRL_RESET_CHIP (1 << 1)
 
 /* Reset the full i.MX23 SoC via a chipset feature */
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn imx23_restart_soc(struct device_d *dev)
 {
 	u32 reg;
 
 	reg = readl(IMX_CCM_BASE + HW_CLKCTRL_RESET);
 	writel(reg | HW_CLKCTRL_RESET_CHIP, IMX_CCM_BASE + HW_CLKCTRL_RESET);
 
-	while (1)
-		;
+	hang();
 	/*NOTREACHED*/
 }
-EXPORT_SYMBOL(reset_cpu);
 
 static int imx23_devices_init(void)
 {
@@ -46,6 +45,7 @@ static int imx23_devices_init(void)
 	add_generic_device("imx23-gpio", 0, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL);
 	add_generic_device("imx23-gpio", 1, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL);
 	add_generic_device("imx23-gpio", 2, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL);
+	restart_register_handler(imx23_restart_soc, NULL, FEATURE_SCOPE_SOC);
 
 	return 0;
 }
diff --git a/arch/arm/mach-mxs/soc-imx28.c b/arch/arm/mach-mxs/soc-imx28.c
index b4ec38d..ed9ae05 100644
--- a/arch/arm/mach-mxs/soc-imx28.c
+++ b/arch/arm/mach-mxs/soc-imx28.c
@@ -16,6 +16,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 #include <mach/imx28-regs.h>
 #include <io.h>
 
@@ -24,18 +25,22 @@
 #define HW_CLKCTRL_WDOG_POR_DISABLE (1 << 5)
 
 /* Reset the full i.MX28 SoC via a chipset feature */
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn imx28_restart_soc(struct device_d *dev)
 {
 	u32 reg;
 
 	reg = readl(IMX_CCM_BASE + HW_CLKCTRL_RESET);
 	writel(reg | HW_CLKCTRL_RESET_CHIP, IMX_CCM_BASE + HW_CLKCTRL_RESET);
 
-	while (1)
-		;
+	hang();
 	/*NOTREACHED*/
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(imx28_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
 
 static int imx28_init(void)
 {
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index 6127dde..7ae1b4c 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -15,8 +15,10 @@
  */
 
 #include <common.h>
+#include <init.h>
 #include <command.h>
 #include <io.h>
+#include <restart.h>
 #include <mach/netx-regs.h>
 #include "eth_firmware.h"
 
@@ -134,14 +136,19 @@ failure:
 	return COMMAND_ERROR_USAGE;
 }
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn netx_restart_soc(struct device_d *dev)
 {
 	SYSTEM_REG(SYSTEM_RES_CR) = 0x01000008;
 
 	/* Not reached */
-	while (1);
+	hang();
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(netx_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
 
 BAREBOX_CMD_START(loadxc)
 	.cmd		= do_loadxc,
diff --git a/arch/arm/mach-nomadik/reset.c b/arch/arm/mach-nomadik/reset.c
index bb5696a..fa9f650 100644
--- a/arch/arm/mach-nomadik/reset.c
+++ b/arch/arm/mach-nomadik/reset.c
@@ -15,10 +15,12 @@
  */
 
 #include <common.h>
+#include <init.h>
 #include <io.h>
+#include <restart.h>
 #include <mach/hardware.h>
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn nomadik_restart_soc(struct device_d *dev)
 {
 	void __iomem *src_rstsr = (void *)(NOMADIK_SRC_BASE + 0x18);
 
@@ -28,6 +30,11 @@ void __noreturn reset_cpu(unsigned long addr)
 	writel(1, src_rstsr);
 
 	/* Not reached */
-	while (1);
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(nomadik_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-omap/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c
index 8ac1290..2bdb569 100644
--- a/arch/arm/mach-omap/am33xx_generic.c
+++ b/arch/arm/mach-omap/am33xx_generic.c
@@ -28,11 +28,11 @@
 #include <mach/gpmc.h>
 #include <restart.h>
 
-void __noreturn am33xx_reset_cpu(unsigned long addr)
+void __noreturn am33xx_restart_soc(struct device_d *dev)
 {
 	writel(AM33XX_PRM_RSTCTRL_RESET, AM33XX_PRM_RSTCTRL);
 
-	while (1);
+	hang();
 }
 
 /**
diff --git a/arch/arm/mach-omap/include/mach/am33xx-generic.h b/arch/arm/mach-omap/include/mach/am33xx-generic.h
index 03418b0..22e2647 100644
--- a/arch/arm/mach-omap/include/mach/am33xx-generic.h
+++ b/arch/arm/mach-omap/include/mach/am33xx-generic.h
@@ -28,7 +28,7 @@ u32 am33xx_running_in_flash(void);
 u32 am33xx_running_in_sram(void);
 u32 am33xx_running_in_sdram(void);
 
-void __noreturn am33xx_reset_cpu(unsigned long addr);
+void __noreturn am33xx_restart_soc(struct device_d *dev);
 
 void am33xx_enable_per_clocks(void);
 int am33xx_init(void);
diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h
index 7db0838..945fe25 100644
--- a/arch/arm/mach-omap/include/mach/omap3-generic.h
+++ b/arch/arm/mach-omap/include/mach/omap3-generic.h
@@ -24,7 +24,7 @@ u32 omap3_running_in_flash(void);
 u32 omap3_running_in_sram(void);
 u32 omap3_running_in_sdram(void);
 
-void __noreturn omap3_reset_cpu(unsigned long addr);
+void __noreturn omap3_restart_soc(struct device_d *dev);
 
 int omap3_init(void);
 int omap3_devices_init(void);
diff --git a/arch/arm/mach-omap/include/mach/omap4-generic.h b/arch/arm/mach-omap/include/mach/omap4-generic.h
index e246e36..dff3330 100644
--- a/arch/arm/mach-omap/include/mach/omap4-generic.h
+++ b/arch/arm/mach-omap/include/mach/omap4-generic.h
@@ -18,7 +18,7 @@ static inline void omap4_save_bootinfo(uint32_t *info)
 	memcpy((void *)OMAP44XX_SRAM_SCRATCH_SPACE, info, 3 * sizeof(uint32_t));
 }
 
-void __noreturn omap4_reset_cpu(unsigned long addr);
+void __noreturn omap4_restart_soc(struct device_d *dev);
 
 int omap4_init(void);
 int omap4_devices_init(void);
diff --git a/arch/arm/mach-omap/omap3_generic.c b/arch/arm/mach-omap/omap3_generic.c
index dbb0b5f..88455ce 100644
--- a/arch/arm/mach-omap/omap3_generic.c
+++ b/arch/arm/mach-omap/omap3_generic.c
@@ -52,13 +52,12 @@
  *
  * @return void
  */
-void __noreturn omap3_reset_cpu(unsigned long addr)
+void __noreturn omap3_restart_soc(struct device_d *dev)
 {
 	writel(OMAP3_PRM_RSTCTRL_RESET, OMAP3_PRM_REG(RSTCTRL));
 
-	while (1);
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
 
 /**
  * @brief Low level CPU type
diff --git a/arch/arm/mach-omap/omap4_generic.c b/arch/arm/mach-omap/omap4_generic.c
index 0b683da..2388d89 100644
--- a/arch/arm/mach-omap/omap4_generic.c
+++ b/arch/arm/mach-omap/omap4_generic.c
@@ -34,11 +34,11 @@
 #define EMIF_L3_CONFIG_VAL_SYS_10_LL_0		0x0A0000FF
 #define EMIF_L3_CONFIG_VAL_SYS_10_MPU_3_LL_0	0x0A300000
 
-void __noreturn omap4_reset_cpu(unsigned long addr)
+void __noreturn omap4_restart_soc(struct device_d *dev)
 {
 	writel(OMAP44XX_PRM_RSTCTRL_RESET, OMAP44XX_PRM_RSTCTRL);
 
-	while (1);
+	hang;
 }
 
 void omap4_set_warmboot_order(u32 *device_list)
diff --git a/arch/arm/mach-omap/omap_generic.c b/arch/arm/mach-omap/omap_generic.c
index 334cf8d..35f576f 100644
--- a/arch/arm/mach-omap/omap_generic.c
+++ b/arch/arm/mach-omap/omap_generic.c
@@ -18,6 +18,7 @@
 #include <boot.h>
 #include <init.h>
 #include <io.h>
+#include <restart.h>
 #include <fs.h>
 #include <malloc.h>
 #include <libfile.h>
@@ -150,16 +151,17 @@ static int omap_env_init(void)
 late_initcall(omap_env_init);
 #endif
 
-void __noreturn reset_cpu(unsigned long addr)
+static int restart_register_feature(void)
 {
 	if (cpu_is_omap3())
-		omap3_reset_cpu(addr);
+		restart_register_handler(omap3_restart_soc, NULL, FEATURE_SCOPE_SOC);
 	if (cpu_is_omap4())
-		omap4_reset_cpu(addr);
+		restart_register_handler(omap4_restart_soc, NULL, FEATURE_SCOPE_SOC);
 	if (cpu_is_am33xx())
-		am33xx_reset_cpu(addr);
-	while (1);
+		restart_register_handler(am33xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
+	return 0;
 }
+coredevice_initcall(restart_register_feature);
 
 static int omap_soc_from_dt(void)
 {
diff --git a/arch/arm/mach-pxa/common.c b/arch/arm/mach-pxa/common.c
index 2c27d81..3d6446d 100644
--- a/arch/arm/mach-pxa/common.c
+++ b/arch/arm/mach-pxa/common.c
@@ -16,6 +16,8 @@
  */
 
 #include <common.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/pxa-regs.h>
 #include <asm/io.h>
 
@@ -29,7 +31,7 @@
 
 extern void pxa_clear_reset_source(void);
 
-void reset_cpu(ulong addr)
+static void __noreturn pxa_restart_soc(struct device_d *dev)
 {
 	/* Clear last reset source */
 	pxa_clear_reset_source();
@@ -39,5 +41,11 @@ void reset_cpu(ulong addr)
 	writel(OSSR_M3, OSSR);
 	writel(readl(OSCR) + 368640, OSMR3);  /* ... in 100 ms */
 
-	while (1);
+	hang();
 }
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(pxa_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-rockchip/core.c b/arch/arm/mach-rockchip/core.c
index bab06df..f59d3d2 100644
--- a/arch/arm/mach-rockchip/core.c
+++ b/arch/arm/mach-rockchip/core.c
@@ -13,16 +13,22 @@
 
 #include <asm/io.h>
 #include <common.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/rockchip-regs.h>
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn rockchip_restart_soc(struct device_d *dev)
 {
 	/* Map bootrom from address 0 */
 	writel(RK_SOC_CON0_REMAP << 16, RK_GRF_BASE + RK_GRF_SOC_CON0);
 	/* Reset */
 	writel(0xeca8, RK_CRU_BASE + RK_CRU_GLB_SRST_SND);
 
-	while (1)
-		;
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(rockchip_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-samsung/generic.c b/arch/arm/mach-samsung/generic.c
index 75965d7..7f7bc36 100644
--- a/arch/arm/mach-samsung/generic.c
+++ b/arch/arm/mach-samsung/generic.c
@@ -21,6 +21,7 @@
 #include <config.h>
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 #include <io.h>
 #include <mach/s3c-iomap.h>
 #include <mach/s3c-generic.h>
@@ -29,7 +30,7 @@
 #define S3C_WTDAT (S3C_WATCHDOG_BASE + 0x04)
 #define S3C_WTCNT (S3C_WATCHDOG_BASE + 0x08)
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn samsung_restart_soc(struct device_d *dev)
 {
 	/* Disable watchdog */
 	writew(0x0000, S3C_WTCON);
@@ -41,7 +42,11 @@ void __noreturn reset_cpu(unsigned long addr)
 	writew(0x0021, S3C_WTCON);
 
 	/* loop forever and wait for reset to happen */
-	while(1)
-		;
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(samsung_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-socfpga/reset-manager.c b/arch/arm/mach-socfpga/reset-manager.c
index a9e7e14..eca1ee3 100644
--- a/arch/arm/mach-socfpga/reset-manager.c
+++ b/arch/arm/mach-socfpga/reset-manager.c
@@ -17,6 +17,8 @@
 
 #include <common.h>
 #include <io.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/socfpga-regs.h>
 #include <mach/reset-manager.h>
 
@@ -38,7 +40,7 @@ void watchdog_disable(void)
 }
 
 /* Write the reset manager register to cause reset */
-void reset_cpu(ulong addr)
+static void __noreturn socfpga_restart_soc(struct device_d *dev)
 {
 	/* request a warm reset */
 	writel((1 << RSTMGR_CTRL_SWWARMRSTREQ_LSB),
@@ -47,5 +49,11 @@ void reset_cpu(ulong addr)
 	 * infinite loop here as watchdog will trigger and reset
 	 * the processor
 	 */
-	while (1);
+	hang();
 }
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(socfpga_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c
index 6493eea..58dca08 100644
--- a/arch/arm/mach-tegra/tegra20-pmc.c
+++ b/arch/arm/mach-tegra/tegra20-pmc.c
@@ -36,13 +36,12 @@ static void __iomem *pmc_base;
 static int tegra_num_powerdomains;
 
 /* main SoC reset trigger */
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn tegra20_restart_soc(struct device_d *dev)
 {
 	writel(PMC_CNTRL_MAIN_RST, pmc_base + PMC_CNTRL);
 
-	unreachable();
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
 
 static int tegra_powergate_set(int id, bool new_state)
 {
@@ -244,6 +243,7 @@ static struct driver_d tegra20_pmc_driver = {
 
 static int tegra20_pmc_init(void)
 {
+	restart_register_handler(tegra20_restart_soc, NULL, FEATURE_SCOPE_SOC);
 	return platform_driver_register(&tegra20_pmc_driver);
 }
 coredevice_initcall(tegra20_pmc_init);
diff --git a/arch/arm/mach-uemd/reset.c b/arch/arm/mach-uemd/reset.c
deleted file mode 100644
index 00ae0be..0000000
--- a/arch/arm/mach-uemd/reset.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com>
- *
- * This file is part of barebox.
- * See file CREDITS for list of people who contributed to this project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * 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 <common.h>
-
-void __noreturn reset_cpu(ulong addr)
-{
-	hang();
-}
-EXPORT_SYMBOL(reset_cpu);
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index c671aa6..e2ceec6 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -26,6 +26,7 @@
 #include <init.h>
 #include <clock.h>
 #include <debug_ll.h>
+#include <restart.h>
 #include <linux/sizes.h>
 
 #include <linux/clkdev.h>
@@ -184,7 +185,7 @@ void versatile_register_uart(unsigned id)
 	amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0);
 }
 
-void __noreturn reset_cpu (unsigned long ignored)
+static void versatile_reset_soc(struct device_d *dev)
 {
 	u32 val;
 
@@ -195,9 +196,8 @@ void __noreturn reset_cpu (unsigned long ignored)
 	__raw_writel(val, VERSATILE_SYS_RESETCTL);
 	__raw_writel(0, VERSATILE_SYS_LOCK);
 
-	while(1);
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
 
 static int versatile_init(void)
 {
@@ -205,6 +205,7 @@ static int versatile_init(void)
 	amba_apb_device_add(NULL, "pl061_gpio", 1, 0x101e5000, 4096, NULL, 0);
 	amba_apb_device_add(NULL, "pl061_gpio", 2, 0x101e6000, 4096, NULL, 0);
 	amba_apb_device_add(NULL, "pl061_gpio", 3, 0x101e7000, 4096, NULL, 0);
+	restart_register_handler(versatile_reset_soc, NULL, FEATURE_SCOPE_SOC);
 	return 0;
 }
 coredevice_initcall(versatile_init);
diff --git a/arch/arm/mach-vexpress/reset.c b/arch/arm/mach-vexpress/reset.c
index ad6e06f..1cbc2b3 100644
--- a/arch/arm/mach-vexpress/reset.c
+++ b/arch/arm/mach-vexpress/reset.c
@@ -6,17 +6,24 @@
 
 #include <common.h>
 #include <io.h>
+#include <init.h>
+#include <restart.h>
 #include <linux/amba/sp805.h>
 
 #include <mach/devices.h>
 
 void __iomem *v2m_wdt_base;
 
-void reset_cpu(ulong addr)
+static void vexpress_reset_soc(struct device_d *dev)
 {
 	writel(LOAD_MIN, v2m_wdt_base + WDTLOAD);
 	writeb(RESET_ENABLE, v2m_wdt_base + WDTCONTROL);
 
-	while (1)
-		;
+	hang();
 }
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(vexpress_reset_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/arm/mach-zynq/zynq.c b/arch/arm/mach-zynq/zynq.c
index bd29e13..b541da1 100644
--- a/arch/arm/mach-zynq/zynq.c
+++ b/arch/arm/mach-zynq/zynq.c
@@ -17,6 +17,7 @@
 #include <asm-generic/io.h>
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 #include <mach/zynq7000-regs.h>
 
 static int zynq_init(void)
@@ -44,13 +45,18 @@ static int zynq_init(void)
 }
 postcore_initcall(zynq_init);
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn zynq_restart_soc(struct device_d *dev)
 {
 	/* write unlock key to slcr */
 	writel(0xDF0D, ZYNQ_SLCR_UNLOCK);
 	/* reset */
 	writel(0x1, ZYNQ_PSS_RST_CTRL);
 
-	while (1)
-		;
+	hang();
 }
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(zynq_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/blackfin/lib/cpu.c b/arch/blackfin/lib/cpu.c
index 9d4c6e3..6c72e03 100644
--- a/arch/blackfin/lib/cpu.c
+++ b/arch/blackfin/lib/cpu.c
@@ -27,8 +27,9 @@
 #include <asm/entry.h>
 #include <asm/cpu.h>
 #include <init.h>
+#include <restart.h>
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn blackfin_restart_cpu(struct device_d *dev)
 {
 	icache_disable();
 
@@ -41,9 +42,15 @@ void __noreturn reset_cpu(unsigned long addr)
 	);
 
 	/* Not reached */
-	while (1);
+	hang();
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(blackfin_restart_cpu, NULL, FEATURE_SCOPE_CPU);
+}
+coredevice_initcall(restart_register_feature);
+
 void icache_disable(void)
 {
 #ifdef __ADSPBF537__
diff --git a/arch/efi/efi/efi.c b/arch/efi/efi/efi.c
index d351775..9d8110b 100644
--- a/arch/efi/efi/efi.c
+++ b/arch/efi/efi/efi.c
@@ -24,6 +24,7 @@
 #include <command.h>
 #include <magicvar.h>
 #include <init.h>
+#include <restart.h>
 #include <driver.h>
 #include <ns16550.h>
 #include <io.h>
@@ -246,13 +247,19 @@ static int efi_console_init(void)
 }
 console_initcall(efi_console_init);
 
-void reset_cpu(unsigned long addr)
+static void __noreturn efi_restart_system(struct device_d *dev)
 {
 	RT->reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
 
-	while(1);
+	hang();
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(efi_restart_cpu, NULL, FEATURE_SCOPE_MACHINE);
+}
+coredevice_initcall(restart_register_feature);
+
 extern char image_base[];
 extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
 		  __barebox_initcalls_end[];
diff --git a/arch/mips/mach-ar231x/ar231x_reset.c b/arch/mips/mach-ar231x/ar231x_reset.c
index 0788add..3724bbe 100644
--- a/arch/mips/mach-ar231x/ar231x_reset.c
+++ b/arch/mips/mach-ar231x/ar231x_reset.c
@@ -10,6 +10,7 @@
 #include <common.h>
 #include <init.h>
 #include <io.h>
+#include <restart.h>
 #include <linux/err.h>
 
 #include <mach/ar2312_regs.h>
@@ -17,16 +18,16 @@
 
 static void __iomem *reset_base;
 
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn ar2312x_restart_soc(struct device_d *dev)
 {
 	printf("reseting cpu\n");
 	__raw_writel(0x10000,
 		(char *)KSEG1ADDR(AR2312_WD_TIMER));
 	__raw_writel(AR2312_WD_CTRL_RESET,
 		(char *)KSEG1ADDR(AR2312_WD_CTRL));
-	unreachable();
+
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
 
 static u32 ar231x_reset_readl(void)
 {
@@ -69,6 +70,7 @@ static struct driver_d ar231x_reset_driver = {
 
 static int ar231x_reset_init(void)
 {
+	restart_register_handler(ar2312x_restart_soc, NULL, FEATURE_SCOPE_SOC);
 	return platform_driver_register(&ar231x_reset_driver);
 }
 coredevice_initcall(ar231x_reset_init);
diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c
index a0e9b34..757027f 100644
--- a/arch/mips/mach-ath79/reset.c
+++ b/arch/mips/mach-ath79/reset.c
@@ -16,9 +16,11 @@
  */
 
 #include <common.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/ath79.h>
 
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn ath79_restart_soc(struct device_d *dev)
 {
 	ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, AR71XX_RESET_FULL_CHIP);
 	/*
@@ -26,7 +28,12 @@ void __noreturn reset_cpu(ulong addr)
 	 * pulling the reset pin. The system will reboot with PLL disabled.
 	 * Always zero when read.
 	 */
-	unreachable();
+	hang();
 	/*NOTREACHED*/
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(ath79_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/mips/mach-bcm47xx/reset.c b/arch/mips/mach-bcm47xx/reset.c
index 00aee19..332047d 100644
--- a/arch/mips/mach-bcm47xx/reset.c
+++ b/arch/mips/mach-bcm47xx/reset.c
@@ -17,12 +17,20 @@
 
 #include <common.h>
 #include <io.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/hardware.h>
 
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn bcm47xx_restart_soc(struct device_d *dev)
 {
 	__raw_writel(GORESET, (char *)SOFTRES_REG);
-	while (1);
+
+	hang();
 	/*NOTREACHED*/
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(bcm47xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/mips/mach-loongson/loongson1_reset.c b/arch/mips/mach-loongson/loongson1_reset.c
index 8975392..fe02da6 100644
--- a/arch/mips/mach-loongson/loongson1_reset.c
+++ b/arch/mips/mach-loongson/loongson1_reset.c
@@ -14,14 +14,21 @@
 
 #include <common.h>
 #include <io.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/loongson1.h>
 
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn longhorn_restart_soc(struct device_d *dev)
 {
 	__raw_writel(0x1, LS1X_WDT_EN);
 	__raw_writel(0x1, LS1X_WDT_SET);
 	__raw_writel(0x1, LS1X_WDT_TIMER);
 
-	unreachable();
+	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(longhorn_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/mips/mach-malta/reset.c b/arch/mips/mach-malta/reset.c
index f1dc68a..066535c 100644
--- a/arch/mips/mach-malta/reset.c
+++ b/arch/mips/mach-malta/reset.c
@@ -22,12 +22,20 @@
 
 #include <common.h>
 #include <io.h>
+#include <init.h>
+#include <restart.h>
 #include <mach/hardware.h>
 
-void __noreturn reset_cpu(ulong addr)
+static void __noreturn malta_restart_soc(struct device_d *dev)
 {
 	__raw_writel(GORESET, (char *)SOFTRES_REG);
-	while (1);
+
+	hang();
 	/*NOTREACHED*/
 }
-EXPORT_SYMBOL(reset_cpu);
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(malta_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/nios2/cpu/cpu.c b/arch/nios2/cpu/cpu.c
index fdbe9f9..3ede3b8 100644
--- a/arch/nios2/cpu/cpu.c
+++ b/arch/nios2/cpu/cpu.c
@@ -18,14 +18,22 @@
  */
 
 #include <common.h>
+#include <init.h>
+#include <restart.h>
 #include <asm/system.h>
 
-void __noreturn reset_cpu(ulong ignored)
+static void __noreturn nios2_restart_soc(struct device_d *dev)
 {
 	/* indirect call to go beyond 256MB limitation of toolchain */
 	nios2_callr(RESET_ADDR);
 
 	/* Not reached */
-	while (1);
+	hang();
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(nios2_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
+
diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c
index d73a418..6cedb26 100644
--- a/arch/openrisc/cpu/cpu.c
+++ b/arch/openrisc/cpu/cpu.c
@@ -19,6 +19,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 #include <asm/system.h>
 #include <asm/openrisc_exc.h>
 
@@ -29,11 +30,17 @@ int cleanup_before_linux(void)
 
 extern void __reset(void);
 
-void __noreturn reset_cpu(ulong ignored)
+static void __noreturn openrisc_restart_cpu(struct device_d *dev)
 {
 	__reset();
 	/* not reached, __reset does not return */
 
 	/* Not reached */
-	while (1);
+	hang();
 }
+
+static int restart_register_feature(void)
+{
+	restart_register_handler(openrisc_restart_cpu, NULL, FEATURE_SCOPE_CPU);
+}
+coredevice_initcall(restart_register_feature);
diff --git a/arch/ppc/mach-mpc5xxx/cpu.c b/arch/ppc/mach-mpc5xxx/cpu.c
index c860e70..c11a6cd 100644
--- a/arch/ppc/mach-mpc5xxx/cpu.c
+++ b/arch/ppc/mach-mpc5xxx/cpu.c
@@ -31,6 +31,7 @@
 #include <types.h>
 #include <errno.h>
 #include <of.h>
+#include <restart.h>
 #include <mach/clocks.h>
 
 int checkcpu (void)
@@ -59,7 +60,7 @@ int checkcpu (void)
 
 /* ------------------------------------------------------------------------- */
 
-void __noreturn reset_cpu (unsigned long addr)
+static void __noreturn mpc5xxx_restart_soc(struct device_d *dev)
 {
 	ulong msr;
 	/* Interrupts and MMU off */
@@ -71,9 +72,15 @@ void __noreturn reset_cpu (unsigned long addr)
 	/* Charge the watchdog timer */
 	*(vu_long *)(MPC5XXX_GPT0_COUNTER) = 0x0001000f;
 	*(vu_long *)(MPC5XXX_GPT0_ENABLE) = 0x9004; /* wden|ce|timer_ms */
-	while(1);
+	hang();
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(mpc5xxx_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
+
 /* ------------------------------------------------------------------------- */
 
 #ifdef CONFIG_OFTREE
diff --git a/arch/ppc/mach-mpc85xx/cpu.c b/arch/ppc/mach-mpc85xx/cpu.c
index 7c183c1..a3fedae 100644
--- a/arch/ppc/mach-mpc85xx/cpu.c
+++ b/arch/ppc/mach-mpc85xx/cpu.c
@@ -26,12 +26,13 @@
 #include <common.h>
 #include <memory.h>
 #include <init.h>
+#include <restart.h>
 #include <asm/fsl_ddr_sdram.h>
 #include <asm-generic/memory_layout.h>
 #include <mach/mmu.h>
 #include <mach/immap_85xx.h>
 
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn mpc85xx_restart_soc(struct device_d *dev)
 {
 	void __iomem *regs = (void __iomem *)MPC85xx_GUTS_ADDR;
 
@@ -39,10 +40,15 @@ void __noreturn reset_cpu(unsigned long addr)
 	out_be32(regs + MPC85xx_GUTS_RSTCR_OFFSET, 0x2);  /* HRESET_REQ */
 	udelay(100);
 
-	while (1)
-		;
+	hang();
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(mpc85xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
+}
+coredevice_initcall(restart_register_feature);
+
 long int initdram(int board_type)
 {
 	phys_size_t dram_size = 0;
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index d627391..61a816e 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -28,6 +28,8 @@
 #include <termios.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <init.h>
+#include <restart.h>
 #include <time.h>
 #include <getopt.h>
 #include <sys/types.h>
@@ -115,12 +117,18 @@ uint64_t linux_get_time(void)
 	return now;
 }
 
-void __attribute__((noreturn)) reset_cpu(unsigned long addr)
+static void __attribute__((noreturn)) sandbox_restart_cpu(struct device_d *dev)
 {
 	cookmode();
 	exit(0);
 }
 
+static int restart_register_feature(void)
+{
+	restart_register_handler(sandbox_restart_cpu, NULL, FEATURE_SCOPE_CPU);
+}
+coredevice_initcall(restart_register_feature);
+
 int linux_read(int fd, void *buf, size_t count)
 {
 	ssize_t ret;
diff --git a/arch/x86/mach-i386/reset.c b/arch/x86/mach-i386/reset.c
deleted file mode 100644
index 65f7d35..0000000
--- a/arch/x86/mach-i386/reset.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2009 Juergen Beisert, Pengutronix
- *
- * 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.
- *
- *
- */
-
-/**
- * @file
- * @brief Resetting an x86 CPU
- */
-
-#include <common.h>
-
-void __noreturn reset_cpu(unsigned long addr)
-{
-	/** How to reset the machine? */
-	while(1)
-		;
-}
-EXPORT_SYMBOL(reset_cpu);
diff --git a/commands/reset.c b/commands/reset.c
index 4f42b91..8300480 100644
--- a/commands/reset.c
+++ b/commands/reset.c
@@ -21,6 +21,7 @@
 #include <command.h>
 #include <complete.h>
 #include <getopt.h>
+#include <restart.h>
 
 static int cmd_reset(int argc, char *argv[])
 {
@@ -39,7 +40,7 @@ static int cmd_reset(int argc, char *argv[])
 	if (shutdown_flag)
 		shutdown_barebox();
 
-	reset_cpu(0);
+	restart_machine();
 
 	/* Not reached */
 	return 1;
diff --git a/common/misc.c b/common/misc.c
index 6da71c7..5532349 100644
--- a/common/misc.c
+++ b/common/misc.c
@@ -24,6 +24,7 @@
 #include <environment.h>
 #include <led.h>
 #include <of.h>
+#include <restart.h>
 
 int errno;
 EXPORT_SYMBOL(errno);
@@ -206,7 +207,7 @@ void __noreturn panic(const char *fmt, ...)
 		hang();
 	} else {
 		udelay(100000);	/* allow messages to go out */
-		reset_cpu(0);
+		restart_machine();
 	}
 }
 EXPORT_SYMBOL(panic);
diff --git a/common/restart.c b/common/restart.c
index f73a9da..67797e4 100644
--- a/common/restart.c
+++ b/common/restart.c
@@ -65,9 +65,64 @@ void reset_source_set(enum reset_src_type st, enum f_scope scope)
 }
 EXPORT_SYMBOL(reset_source_set);
 
+/* handle machine restart feature */
+
+static struct device_d *resetd;
+static void (*resetf)(struct device_d*);
+static int restart_scope;
+
+void __noreturn restart_machine(void)
+{
+	if (resetf != NULL)
+		resetf(resetd);
+	else
+		pr_err("No restart handler available. Cannot restart system, hanging instead\n");
+
+	hang();
+}
+
+static void restart_update_global_info(void)
+{
+	globalvar_add_simple("system.restart.unit",
+				resetd == NULL ? "unknown" : resetd->name);
+	globalvar_add_simple_enum("system.reset.scope", &restart_scope,
+					scope_names, ARRAY_SIZE(scope_names));
+}
+
+int restart_register_handler(void (*func)(struct device_d*), struct device_d *dev, enum f_scope scope)
+{
+	/* calling with a lower or equal scope will be ignored and is not a failure */
+	if ((int)scope <= restart_scope)
+		return 0;
+
+	resetf = func;
+	resetd = dev;
+	restart_scope = (int)scope;
+	restart_update_global_info();
+
+	return 0;
+}
+EXPORT_SYMBOL(restart_register_handler);
+
+int restart_remove_handler(void (*func)(struct device_d*), struct device_d *dev)
+{
+	/* we just ignore a not matching call */
+	if (func != resetf || resetd != dev)
+		return 0;
+
+	resetf = NULL;
+	resetd = NULL;
+	restart_scope = (int)FEATURE_SCOPE_UNKNOWN;
+	restart_update_global_info();
+
+	return 0;
+}
+EXPORT_SYMBOL(restart_remove_handler);
+
 static int reset_feature_init(void)
 {
 	reset_source_update_global_info();
+	restart_update_global_info();
 	return 0;
 }
 coredevice_initcall(reset_feature_init);
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 76879db..bf28f7c 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -31,6 +31,7 @@
 #include <progress.h>
 #include <environment.h>
 #include <globalvar.h>
+#include <restart.h>
 #include <usb/ch9.h>
 #include <usb/gadget.h>
 #include <usb/fastboot.h>
@@ -520,7 +521,7 @@ static int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
 
 static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
 {
-	reset_cpu(0);
+	restart_machine();
 }
 
 static void cb_reboot(struct usb_ep *ep, struct usb_request *req, const char *cmd)
diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
index f3decae..3cbae09 100644
--- a/drivers/watchdog/imxwd.c
+++ b/drivers/watchdog/imxwd.c
@@ -121,12 +121,11 @@ static int imx_watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
 	return priv->ops->set_timeout(priv, timeout);
 }
 
-static struct imx_wd *reset_wd;
-
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn imxwd_force_soc_reset(struct device_d *dev)
 {
-	if (reset_wd)
-		reset_wd->ops->set_timeout(reset_wd, -1);
+	struct imx_wd *reset_wd = dev->priv;
+
+	reset_wd->ops->set_timeout(reset_wd, -1);
 
 	mdelay(1000);
 
@@ -158,6 +157,7 @@ static void imx_watchdog_detect_reset_source(struct imx_wd *priv)
 static int imx21_wd_init(struct imx_wd *priv)
 {
 	imx_watchdog_detect_reset_source(priv);
+	restart_register_handler(imxwd_force_soc_reset, priv->dev, FEATURE_SCOPE_SOC);
 
 	/*
 	 * Disable watchdog powerdown counter
@@ -187,9 +187,6 @@ static int imx_wd_probe(struct device_d *dev)
 	priv->wd.set_timeout = imx_watchdog_set_timeout;
 	priv->dev = dev;
 
-	if (!reset_wd)
-		reset_wd = priv;
-
 	if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) {
 		ret = watchdog_register(&priv->wd);
 		if (ret)
@@ -212,8 +209,7 @@ error_unregister:
 	if (IS_ENABLED(CONFIG_WATCHDOG_IMX))
 		watchdog_deregister(&priv->wd);
 on_error:
-	if (reset_wd && reset_wd != priv)
-		free(priv);
+	free(priv);
 	return ret;
 }
 
@@ -221,11 +217,12 @@ static void imx_wd_remove(struct device_d *dev)
 {
 	struct imx_wd *priv = dev->priv;
 
+	restart_remove_handler(imxwd_force_soc_reset, dev);
+
 	if (IS_ENABLED(CONFIG_WATCHDOG_IMX))
 		watchdog_deregister(&priv->wd);
 
-	if (reset_wd && reset_wd != priv)
-		free(priv);
+	free(priv);
 }
 
 static const struct imx_wd_ops imx21_wd_ops = {
diff --git a/drivers/watchdog/jz4740.c b/drivers/watchdog/jz4740.c
index 8ac51e0..dcaa62f 100644
--- a/drivers/watchdog/jz4740.c
+++ b/drivers/watchdog/jz4740.c
@@ -16,6 +16,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <restart.h>
 #include <io.h>
 
 #define JZ_REG_WDT_TIMER_DATA     0x0
@@ -42,30 +43,26 @@ struct jz4740_wdt_drvdata {
 	void __iomem *base;
 };
 
-static struct jz4740_wdt_drvdata *reset_wd;
-
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn jz4740_reset_soc(struct device_d *dev)
 {
-	if (reset_wd) {
-		void __iomem *base = reset_wd->base;
+	struct jz4740_wdt_drvdata *reset_wd = dev->priv;
+
+	void __iomem *base = reset_wd->base;
 
-		writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT,
-				base + JZ_REG_WDT_TIMER_CONTROL);
-		writew(0, base + JZ_REG_WDT_TIMER_COUNTER);
+	writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT,
+			base + JZ_REG_WDT_TIMER_CONTROL);
+	writew(0, base + JZ_REG_WDT_TIMER_COUNTER);
 
-		/* reset after 4ms */
-		writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA);
+	/* reset after 4ms */
+	writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA);
 
-		/* start wdt */
-		writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE);
+	/* start wdt */
+	writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE);
 
-		mdelay(1000);
-	} else
-		pr_err("%s: can't reset cpu\n", __func__);
+	mdelay(1000);
 
 	hang();
 }
-EXPORT_SYMBOL(reset_cpu);
 
 static int jz4740_wdt_probe(struct device_d *dev)
 {
@@ -78,11 +75,9 @@ static int jz4740_wdt_probe(struct device_d *dev)
 		return -ENODEV;
 	}
 
-	if (!reset_wd)
-		reset_wd = priv;
-
 	dev->priv = priv;
 
+	restart_register_handler(jz4740_reset_soc, dev, FEATURE_SCOPE_SOC);
 	return 0;
 }
 
diff --git a/include/common.h b/include/common.h
index eef371c..e658593 100644
--- a/include/common.h
+++ b/include/common.h
@@ -67,7 +67,6 @@ int	readline	(const char *prompt, char *buf, int len);
 long	get_ram_size  (volatile long *, long);
 
 /* $(CPU)/cpu.c */
-void __noreturn reset_cpu(unsigned long addr);
 void __noreturn poweroff(void);
 
 /* lib_$(ARCH)/time.c */
diff --git a/include/restart.h b/include/restart.h
index 4215760..a74383b 100644
--- a/include/restart.h
+++ b/include/restart.h
@@ -37,4 +37,10 @@ enum reset_src_type {
 void reset_source_set(enum reset_src_type, enum f_scope);
 enum reset_src_type reset_source_get(void);
 
+/* restart feature */
+
+int restart_register_handler(void (*func)(struct device_d*), struct device_d *, enum f_scope);
+int restart_remove_handler(void (*func)(struct device_d*), struct device_d *);
+void __noreturn restart_machine(void);
+
 #endif /* __INCLUDE_SYSTEM_RESTART_H */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/5] Watchdog: add a scope value to the watchdog feature
  2015-06-23 12:57 [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
  2015-06-23 12:58 ` [PATCH 1/5] Reset reason: add a scope value to the reset reason feature Juergen Borleis
  2015-06-23 12:58 ` [PATCH 2/5] System restart: add a scope value to the system restart feature Juergen Borleis
@ 2015-06-23 12:58 ` Juergen Borleis
  2015-06-24  6:51   ` Sascha Hauer
  2015-06-23 12:58 ` [PATCH 4/5] Watchdog/i.MX: make the watchdog driver a regular driver Juergen Borleis
  2015-06-23 12:58 ` [PATCH 5/5] MFD/DA9053: da9053: add basic da9053 driver Juergen Borleis
  4 siblings, 1 reply; 11+ messages in thread
From: Juergen Borleis @ 2015-06-23 12:58 UTC (permalink / raw)
  To: barebox

Sometimes the SoC internal watchdogs are inappropriate to restart the
machine in a reliable manner. This change should help to handle more than
one watchdog unit by adding a scope parameter. The framework always
prefers the watchdog with the widest scope. For example a watchdog
which is able to restart the whole machine (SoC + external devices) gets
precedence over a watchdog which can restart the SoC only.

Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 Documentation/user/user-manual.rst |  1 +
 Documentation/user/watchdog.rst    | 74 ++++++++++++++++++++++++++++++++++++++
 common/restart.c                   |  6 ++++
 drivers/watchdog/im28wd.c          |  1 +
 drivers/watchdog/imxwd.c           |  1 +
 drivers/watchdog/wd_core.c         | 24 +++++++++++--
 include/watchdog.h                 |  3 ++
 7 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/user/watchdog.rst

diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
index 0d6daee..8a32469 100644
--- a/Documentation/user/user-manual.rst
+++ b/Documentation/user/user-manual.rst
@@ -30,6 +30,7 @@ Contents:
    system-setup
    reset-reason
    system-reset
+   watchdog
 
 * :ref:`search`
 * :ref:`genindex`
diff --git a/Documentation/user/watchdog.rst b/Documentation/user/watchdog.rst
new file mode 100644
index 0000000..d8e6e76
--- /dev/null
+++ b/Documentation/user/watchdog.rst
@@ -0,0 +1,74 @@
+.. _watchdog_usage:
+
+Using a watchdog
+----------------
+
+Watchdogs are commonly used to prevent bad software from hanging the whole
+system for ever. Sometimes a simple approach can help to make a system work
+if hanging failures are happen very seldom: just restart the system and do
+everything again in the same way as it was done when the system starts the
+last time.
+
+But using a watchdog should always be the 'last resort' to keep a machine
+working. The focus should still be on finding and fixing the bug ;)
+
+A more complex way to use a watchdog in a real-word example is when the state
+frameworks comes into play. Then the watchdog's task isn't only to keep the
+machine working. It also monitors the whole health of the machine including
+hardware and software. Especially something like a firmware update can go
+wrong: a wrong firmware was programmed (wrong release or for a different machine),
+programming was incomplete due to a user intervention or power fail and so on.
+
+In this case the watchdog does not just restart the system if the software hangs,
+it also provides 'additional' information about the firmware by this restart.
+The barebox's state framework is now able to run some kind of state machine to handle
+firmware updates in a correct manner: trying the new firmware once and if it fails falling
+back to the previous firmware (if available) for example.
+
+Refer the :ref:`reset_reason` how to detect the reason why the bootloader runs.
+This information can be used by the barebox's state framework.
+
+.. _watchdog_restart_pitfalls:
+
+Watchdog Pitfalls
+~~~~~~~~~~~~~~~~~
+
+If a watchdog triggers a machine restart it suffers from the same issues like
+a regular user triggered system machine restart. Refer :ref:`system_reset_pitfalls`
+for further details.
+So keep this in mind when you select an available watchdog on your machine for
+this task. And if you are a hardware designer keep this in mind even more, and
+provide a reliable restart source for the software developers and to keep their
+headache low.
+
+Watchdogs from the developers point of view
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Watchdogs gets registered in barebox with a scope. When you register your own
+watchdog driver, check its hardware scope carefully and use one of the
+definitions from the file ``include/restart.h``.
+
+The list of defined scopes (defined in file ``include/restart.h``):
+
+* ``FEATURE_SCOPE_UNKNOWN``: completely useless watchdog, maybe a last resort..
+* ``FEATURE_SCOPE_CPU``: this watchdog is able to restart the core CPU only.
+  Regarding to the issues in :ref:`system_reset_pitfalls` this kind of watchdog
+  seems more or less useless.
+* ``FEATURE_SCOPE_SOC``: this watchdog is able to restart the whole SoC. Regarding
+  to the issues in :ref:`system_reset_pitfalls` this scope is more reliable, but
+  depends on the machine and its hardware design if is able to bring the machine
+  back into life under every circumstance.
+* ``FEATURE_SCOPE_MACHINE``: it is able to restart the whole machine and does
+  the same like a real ``POR`` does. Best scope and always reliable.
+
+The selected scope is very important because barebox will always use
+the watchdog with the best available scope.
+
+But that is true only for watchdogs used in barebox and as long barebox is
+running.
+
+If an operating system runs later on, it is the task of this OS to use a watchdog
+with a correct scope. Otherwise it suffers from the :ref:`system_reset_pitfalls`
+as well. This is even more important if the state framework is used. That means
+barebox and the operating system must use the same watchdog in order to check
+and change the states correctly.
diff --git a/common/restart.c b/common/restart.c
index 67797e4..c0c4861 100644
--- a/common/restart.c
+++ b/common/restart.c
@@ -119,6 +119,12 @@ int restart_remove_handler(void (*func)(struct device_d*), struct device_d *dev)
 }
 EXPORT_SYMBOL(restart_remove_handler);
 
+void watchdog_update_global_info(int *scope)
+{
+	globalvar_add_simple_enum("system.wd.scope", scope,
+				scope_names, ARRAY_SIZE(scope_names));
+}
+
 static int reset_feature_init(void)
 {
 	reset_source_update_global_info();
diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c
index c824a25..918d37a 100644
--- a/drivers/watchdog/im28wd.c
+++ b/drivers/watchdog/im28wd.c
@@ -197,6 +197,7 @@ static int imx28_wd_probe(struct device_d *dev)
 	if (IS_ERR(priv->regs))
 		return PTR_ERR(priv->regs);
 	priv->wd.set_timeout = imx28_watchdog_set_timeout;
+	priv->wd.scope = FEATURE_SCOPE_SOC;
 
 	if (!(readl(priv->regs + MXS_RTC_STAT) & MXS_RTC_STAT_WD_PRESENT)) {
 		rc = -ENODEV;
diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
index 3cbae09..60772b1 100644
--- a/drivers/watchdog/imxwd.c
+++ b/drivers/watchdog/imxwd.c
@@ -185,6 +185,7 @@ static int imx_wd_probe(struct device_d *dev)
 	}
 	priv->ops = ops;
 	priv->wd.set_timeout = imx_watchdog_set_timeout;
+	priv->wd.scope = FEATURE_SCOPE_SOC;
 	priv->dev = dev;
 
 	if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) {
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index 3d0cfc6..6386cf3 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -13,22 +13,32 @@
  */
 
 #include <common.h>
+#include <init.h>
 #include <command.h>
 #include <errno.h>
 #include <linux/ctype.h>
 #include <watchdog.h>
+#include <globalvar.h>
+#include <restart.h>
 
 /*
  * Note: this simple framework supports one watchdog only.
  */
 static struct watchdog *watchdog;
+static int watchdog_scope;
+
+void watchdog_update_global_info(int*);
 
 int watchdog_register(struct watchdog *wd)
 {
-	if (watchdog != NULL)
-		return -EBUSY;
+	/* ignore a lower or same priority, it isn't a failure */
+	if (wd->scope <= watchdog_scope)
+		return 0;
 
 	watchdog = wd;
+	watchdog_scope = (int)wd->scope;
+	watchdog_update_global_info(&watchdog_scope);
+
 	return 0;
 }
 EXPORT_SYMBOL(watchdog_register);
@@ -39,6 +49,9 @@ int watchdog_deregister(struct watchdog *wd)
 		return -ENODEV;
 
 	watchdog = NULL;
+	watchdog_scope = (int)FEATURE_SCOPE_UNKNOWN;
+	watchdog_update_global_info(&watchdog_scope);
+
 	return 0;
 }
 EXPORT_SYMBOL(watchdog_deregister);
@@ -55,3 +68,10 @@ int watchdog_set_timeout(unsigned timeout)
 	return watchdog->set_timeout(watchdog, timeout);
 }
 EXPORT_SYMBOL(watchdog_set_timeout);
+
+static int watchdog_capability_init(void)
+{
+	watchdog_update_global_info(&watchdog_scope);
+	return 0;
+}
+coredevice_initcall(watchdog_capability_init);
diff --git a/include/watchdog.h b/include/watchdog.h
index 7e37b7c..e7047bb 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -13,8 +13,11 @@
 #ifndef INCLUDE_WATCHDOG_H
 # define INCLUDE_WATCHDOG_H
 
+#include <restart.h>
+
 struct watchdog {
 	int (*set_timeout)(struct watchdog *, unsigned);
+	enum f_scope scope;
 };
 
 #ifdef CONFIG_WATCHDOG
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 4/5] Watchdog/i.MX: make the watchdog driver a regular driver
  2015-06-23 12:57 [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
                   ` (2 preceding siblings ...)
  2015-06-23 12:58 ` [PATCH 3/5] Watchdog: add a scope value to the watchdog feature Juergen Borleis
@ 2015-06-23 12:58 ` Juergen Borleis
  2015-06-23 12:58 ` [PATCH 5/5] MFD/DA9053: da9053: add basic da9053 driver Juergen Borleis
  4 siblings, 0 replies; 11+ messages in thread
From: Juergen Borleis @ 2015-06-23 12:58 UTC (permalink / raw)
  To: barebox

Even if the driver for the internal watchdog unit is disabled, it gets
enabled again silently if we select an i.MX platform.

This change compiles the driver on user demand only. Barebox can handle one
watchdog and one reset source. This change enables a user to select a
different one if the built-in unit cannot be used due to hardware issues like
power management and voltage changes the internal watchdog cannot reset
correctly.

Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 arch/arm/Kconfig          | 1 -
 drivers/watchdog/Kconfig  | 3 ---
 drivers/watchdog/Makefile | 2 +-
 3 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 50f3095..b115d10 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -101,7 +101,6 @@ config ARCH_IMX
 	select GPIOLIB
 	select COMMON_CLK
 	select CLKDEV_LOOKUP
-	select WATCHDOG_IMX_RESET_SOURCE
 	select HAS_DEBUG_LL
 
 config ARCH_MVEBU
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 7f7b02e..f43c101 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1,7 +1,4 @@
 
-config WATCHDOG_IMX_RESET_SOURCE
-	bool
-
 menuconfig WATCHDOG
 	bool "Watchdog support"
 	help
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 865fc47..446056d 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_WATCHDOG) += wd_core.o
 obj-$(CONFIG_WATCHDOG_MXS28) += im28wd.o
 obj-$(CONFIG_WATCHDOG_JZ4740) += jz4740.o
-obj-$(CONFIG_WATCHDOG_IMX_RESET_SOURCE) += imxwd.o
+obj-$(CONFIG_WATCHDOG_IMX) += imxwd.o
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 5/5] MFD/DA9053: da9053: add basic da9053 driver
  2015-06-23 12:57 [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
                   ` (3 preceding siblings ...)
  2015-06-23 12:58 ` [PATCH 4/5] Watchdog/i.MX: make the watchdog driver a regular driver Juergen Borleis
@ 2015-06-23 12:58 ` Juergen Borleis
  4 siblings, 0 replies; 11+ messages in thread
From: Juergen Borleis @ 2015-06-23 12:58 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 drivers/mfd/Kconfig  |   8 ++
 drivers/mfd/Makefile |   1 +
 drivers/mfd/da9053.c | 337 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 346 insertions(+)
 create mode 100644 drivers/mfd/da9053.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3af904d..6ec66ac 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -4,6 +4,14 @@ config MFD_ACT8846
 	depends on I2C
 	bool "ACT8846 driver"
 
+config MFD_DA9053
+	depends on I2C
+	bool "DA9053 PMIC driver"
+	help
+	  This power management controller provides configureable power supplies,
+	  a machine restart feature and a watchdog which are effective machine
+	  wide.
+
 config MFD_LP3972
 	depends on I2C
 	bool "LP3972 driver"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 49b9e35..2899dde 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_MFD_ACT8846)	+= act8846.o
+obj-$(CONFIG_MFD_DA9053)	+= da9053.o
 obj-$(CONFIG_MFD_LP3972)	+= lp3972.o
 obj-$(CONFIG_MFD_MC13XXX)	+= mc13xxx.o
 obj-$(CONFIG_MFD_MC34704)	+= mc34704.o
diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c
new file mode 100644
index 0000000..6e86195
--- /dev/null
+++ b/drivers/mfd/da9053.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2013 Jan Luebbe <jlu@pengutronix.de>
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <watchdog.h>
+
+#include <i2c/i2c.h>
+#include <restart.h>
+#include <restart.h>
+
+#define DRIVERNAME		"da9053"
+
+/* STATUS REGISTERS */
+#define DA9053_STATUS_A_REG		1
+#define DA9053_STATUS_B_REG		2
+#define DA9053_STATUS_C_REG		3
+#define DA9053_STATUS_D_REG		4
+
+/* PARK REGISTER */
+#define DA9053_PARK_REGISTER		DA9053_STATUS_D_REG
+
+/* EVENT REGISTERS */
+#define DA9053_EVENT_A_REG		5
+#define DA9053_EVENT_B_REG		6
+#define DA9053_EVENT_C_REG		7
+#define DA9053_EVENT_D_REG		8
+#define DA9053_FAULTLOG_REG		9
+
+/* IRQ REGISTERS */
+#define DA9053_IRQ_MASK_A_REG		10
+#define DA9053_IRQ_MASK_B_REG		11
+#define DA9053_IRQ_MASK_C_REG		12
+#define DA9053_IRQ_MASK_D_REG		13
+
+/* CONTROL REGISTERS */
+#define DA9053_CONTROL_A_REG		14
+#define DA9053_CONTROL_B_REG		15
+#define DA9053_CONTROL_C_REG		16
+#define DA9053_CONTROL_D_REG		17
+
+#define DA9053_PDDIS_REG		18
+#define DA9053_INTERFACE_REG		19
+#define DA9053_RESET_REG		20
+
+/* FAULT LOG REGISTER BITS */
+#define DA9053_FAULTLOG_WAITSET		0X80
+#define DA9053_FAULTLOG_NSDSET		0X40
+#define DA9053_FAULTLOG_KEYSHUT		0X20
+#define DA9053_FAULTLOG_TEMPOVER	0X08
+#define DA9053_FAULTLOG_VDDSTART	0X04
+#define DA9053_FAULTLOG_VDDFAULT	0X02
+#define DA9053_FAULTLOG_TWDERROR	0X01
+
+/* CONTROL REGISTER B BITS */
+#define DA9053_CONTROLB_SHUTDOWN	0X80
+#define DA9053_CONTROLB_DEEPSLEEP	0X40
+#define DA9053_CONTROLB_WRITEMODE	0X20
+#define DA9053_CONTROLB_BBATEN		0X10
+#define DA9053_CONTROLB_OTPREADEN	0X08
+#define DA9053_CONTROLB_AUTOBOOT	0X04
+#define DA9053_CONTROLB_ACTDIODE	0X02
+#define DA9053_CONTROLB_BUCKMERGE	0X01
+
+/* CONTROL REGISTER D BITS */
+#define DA9053_CONTROLD_WATCHDOG	0X80
+#define DA9053_CONTROLD_ACCDETEN	0X40
+#define DA9053_CONTROLD_GPI1415SD	0X20
+#define DA9053_CONTROLD_NONKEYSD	0X10
+#define DA9053_CONTROLD_KEEPACTEN	0X08
+#define DA9053_CONTROLD_TWDSCALE	0X07
+
+struct da9053_priv {
+	struct cdev		cdev;
+	struct watchdog		wd;
+	struct i2c_client	*client;
+};
+
+#define cdev_to_da9053_priv(x)	container_of(x, struct da9053_priv, cdev)
+#define wd_to_da9053_priv(x)	container_of(x, struct da9053_priv, wd)
+
+static int da9053_reg_read(struct da9053_priv *da9053, u32 reg, u8 *val)
+{
+	int ret;
+
+	ret = i2c_read_reg(da9053->client, reg, val, 1);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static int da9053_reg_write(struct da9053_priv *da9053, u32 reg, u8 val)
+{
+	int ret;
+
+	ret = i2c_write_reg(da9053->client, reg, &val, 1);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static int da9053_park(struct da9053_priv *da9053)
+{
+	int ret;
+	u8 val;
+
+	ret = i2c_read_reg(da9053->client, DA9053_PARK_REGISTER, &val, 1);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static ssize_t da9053_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+	struct da9053_priv *da9053 = cdev_to_da9053_priv(cdev);
+	u8 *buf = _buf;
+	size_t i = count;
+	int err;
+
+	while (i) {
+		err = da9053_reg_read(da9053, offset, buf);
+		if (err) {
+			da9053_park(da9053);
+			return (ssize_t)err;
+		}
+		buf++;
+		i--;
+		offset++;
+	}
+
+	if (da9053_park(da9053) < 0)
+		return -EIO;
+
+	return count;
+}
+
+static int da9053_enable_multiwrite(struct da9053_priv *da9053)
+{
+	int ret;
+	u8 val;
+
+	ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val & DA9053_CONTROLB_WRITEMODE) {
+		val &= ~DA9053_CONTROLB_WRITEMODE;
+		ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = da9053_park(da9053);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct file_operations da9053_fops = {
+	.lseek	= dev_lseek_default,
+	.read	= da9053_read,
+};
+
+static int da9053_set_timeout(struct watchdog *wd, unsigned timeout)
+{
+	struct da9053_priv *da9053 = wd_to_da9053_priv(wd);
+	struct device_d *dev = da9053->cdev.dev;
+	unsigned scale = 0;
+	int ret;
+	u8 val;
+
+	if (timeout > 131)
+		return -EINVAL;
+
+	if (timeout) {
+		timeout *= 1000; /* convert to ms */
+		scale = 0;
+		while (timeout > (2048 << scale) && scale <= 6)
+			scale++;
+		dev_dbg(dev, "calculated TWDSCALE=%u (req=%ims calc=%ims)\n",
+		        scale, timeout, 2048 << scale);
+		scale++; /* scale 0 disables the WD */
+	}
+
+	ret = da9053_reg_read(da9053, DA9053_CONTROL_D_REG, &val);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "read watchdog (val=0x%02x)\n", val);
+
+	if (scale && scale == (val & DA9053_CONTROLD_TWDSCALE)) {
+		/* trigger WD */
+		val |= DA9053_CONTROLD_WATCHDOG;
+		ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+		if (ret < 0)
+			return ret;
+		dev_dbg(dev, "triggered watchdog (val=0x%02x)\n", val);
+	} else {
+		/* disable WD first */
+		val &= ~DA9053_CONTROLD_TWDSCALE;
+		ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+		if (ret < 0)
+			return ret;
+
+		dev_dbg(dev, "disabled watchdog (val=0x%02x)\n", val);
+		if (scale) {
+			/* park before waiting */
+			ret = da9053_park(da9053);
+			if (ret < 0)
+				return ret;
+
+			/* wait required time */
+			udelay(150);
+
+			/* enable WD with new timeout */
+			val |= scale;
+			ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+			if (ret < 0)
+				return ret;
+			dev_dbg(dev, "enabled watchdog (val=0x%02x)\n", val);
+		}
+	}
+
+	ret = da9053_park(da9053);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void da9053_detect_reset_source(struct da9053_priv *da9053)
+{
+	int ret;
+	u8 val;
+
+	ret = da9053_reg_read(da9053, DA9053_FAULTLOG_REG, &val);
+	if (ret < 0)
+		return;
+
+	ret = da9053_park(da9053);
+	if (ret < 0)
+		return;
+
+	if (val & DA9053_FAULTLOG_TWDERROR) {
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_MACHINE);
+		return;
+	}
+
+	if (val & DA9053_FAULTLOG_VDDFAULT) {
+		reset_source_set(RESET_POR, FEATURE_SCOPE_MACHINE);
+		return;
+	}
+
+	if (val & DA9053_FAULTLOG_NSDSET) {
+		reset_source_set(RESET_RST, FEATURE_SCOPE_MACHINE);
+		return;
+	}
+
+	/* else keep the default 'unknown' state */
+}
+
+static void __noreturn da9053_force_system_reset(struct device_d *dev)
+{
+	struct da9053_priv *da9053 = dev->priv;
+	u8 val;
+	int ret;
+
+	ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val);
+	if (ret < 0)
+		hang();
+
+	val |= DA9053_CONTROLB_SHUTDOWN;
+	ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val);
+	if (ret < 0)
+		hang();
+
+	da9053_park(da9053);
+
+	hang();
+}
+
+static int da9053_probe(struct device_d *dev)
+{
+	struct da9053_priv *da9053;
+	int ret;
+
+	da9053 = xzalloc(sizeof(struct da9053_priv));
+	dev->priv = da9053;
+	da9053->cdev.name = DRIVERNAME;
+	da9053->client = to_i2c_client(dev);
+	da9053->cdev.size = 128;
+	da9053->cdev.dev = dev;
+	da9053->cdev.ops = &da9053_fops;
+	da9053->wd.set_timeout = da9053_set_timeout;
+	da9053->wd.scope = FEATURE_SCOPE_MACHINE;
+
+	ret = da9053_enable_multiwrite(da9053);
+	if (ret < 0)
+		return ret;
+
+	ret = watchdog_register(&da9053->wd);
+	if (ret)
+		return ret;
+
+	da9053_detect_reset_source(da9053);
+
+	restart_register_handler(da9053_force_system_reset, dev, FEATURE_SCOPE_MACHINE);
+
+	return 0;
+}
+
+static struct driver_d da9053_driver = {
+	.name  = DRIVERNAME,
+	.probe = da9053_probe,
+};
+
+static int da9053_init(void)
+{
+	i2c_driver_register(&da9053_driver);
+	return 0;
+}
+
+device_initcall(da9053_init);
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/5] Reset reason: add a scope value to the reset reason feature
  2015-06-23 12:58 ` [PATCH 1/5] Reset reason: add a scope value to the reset reason feature Juergen Borleis
@ 2015-06-24  6:32   ` Sascha Hauer
  2015-06-24  7:35     ` Juergen Borleis
  0 siblings, 1 reply; 11+ messages in thread
From: Sascha Hauer @ 2015-06-24  6:32 UTC (permalink / raw)
  To: Juergen Borleis; +Cc: barebox

On Tue, Jun 23, 2015 at 02:58:00PM +0200, Juergen Borleis wrote:
> Some systems do have more than one source to detect the reason of a reset.
> In this case it depends on the initialization order which reason will be
> reported to barebox. To avoid this race, this change adds a scope to the
> function call to always accept settings with a wider scope and ignore
> all settings with a limited scope.
> 
> This change is required to support systems where one reset reason source
> is more reliable than other sources. Examples are all i.MX SoCs with
> an internal reset reason detector and an external PMIC which has the same
> capabilities. For these systems the external PMIC provides the correct
> reset cause while the internal unit flags a POR only all the time. In order
> to support one binary for more than one machine we cannot just disable the
> internal reset reason detector, so we need this scope mechanism.
> 
> Assumption in this change is, the reset cause sources with a wider scope are
> always reporting the correct reason and not vice versa.
> 
> Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
> ---
>  Documentation/user/reset-reason.rst   | 30 ++++++++++++++
>  Documentation/user/system-reset.rst   |  3 +-
>  arch/arm/mach-imx/imx1.c              |  8 ++--
>  arch/arm/mach-omap/am33xx_generic.c   | 14 +++----
>  arch/arm/mach-pxa/pxa2xx.c            | 12 +++---
>  arch/arm/mach-pxa/pxa3xx.c            | 12 +++---
>  arch/arm/mach-samsung/reset_source.c  |  8 ++--
>  arch/arm/mach-tegra/tegra20-pmc.c     | 14 +++----
>  common/Kconfig                        |  8 ----
>  common/Makefile                       |  2 +-
>  common/reset_source.c                 | 56 ---------------------------
>  common/restart.c                      | 73 +++++++++++++++++++++++++++++++++++
>  drivers/watchdog/im28wd.c             | 12 +++---
>  drivers/watchdog/imxwd.c              |  8 ++--
>  include/{reset_source.h => restart.h} | 29 +++++++-------
>  15 files changed, 164 insertions(+), 125 deletions(-)
>  delete mode 100644 common/reset_source.c
>  create mode 100644 common/restart.c
>  rename include/{reset_source.h => restart.h} (71%)
> 
> diff --git a/Documentation/user/reset-reason.rst b/Documentation/user/reset-reason.rst
> index a4872fa..525ade2 100644
> --- a/Documentation/user/reset-reason.rst
> +++ b/Documentation/user/reset-reason.rst
> @@ -3,6 +3,9 @@
>  Reset Reason
>  ------------
>  
> +Using the Reset Reason
> +~~~~~~~~~~~~~~~~~~~~~~
> +
>  To handle a device in a secure and safty manner many applications are using
>  a watchdog or other ways to reset a system to bring it back into life if it
>  hangs or crashes somehow.
> @@ -45,3 +48,30 @@ The following values can help to detect the reason why the bootloader runs:
>  It depends on your board/SoC and its features if the hardware is able to detect
>  these reset reasons. Most of the time only ``POR`` and ``RST`` are supported
>  but often ``WDG`` as well.
> +
> +.. _reset_reason_scope:
> +
> +Scope of Reset Reason
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +Some machines can detect the reset reason via different devices, for example
> +via a SoC internal devices and an externally attached device. Both can provide
> +the correct reason - or not. If their reset reason point of view differ, you
> +need a ``scope`` to decide what reason is the correct one. Barebox provides
> +the reset reason scope via the global variable ``system.reset.scope`` and
> +the following values:
> +
> +* ``unknown``: the software can't define the scope of the reset reason.
> +* ``cpu``: the inner core CPU only point of view.
> +* ``soc``: the full SoC point of view.
> +* ``machine``: the full machine point of view
> +
> +The scopes are rated: lowest rate is ``unknown`` and ``cpu``. The highest
> +rate has the ``machine`` point of view. The ``soc`` point of view in inbetween.
> +
> +Why can the reset reason differ due to different scopes? Think about a SoC which
> +is powered by a PMIC: the reset reason detection inside the SoC has the ``soc``
> +scope, the PMIC's reset reason detection has the ``machine`` scope. In this case
> +the ``soc`` scope reset reason is always ``POR``, while the ``machine`` scope
> +reset reason is ``POR`` only on a real POR, ``RST`` due to an user
> +intervention and ``WDG`` because the system has failed somehow.
> diff --git a/Documentation/user/system-reset.rst b/Documentation/user/system-reset.rst
> index e76e3a2..e902026 100644
> --- a/Documentation/user/system-reset.rst
> +++ b/Documentation/user/system-reset.rst
> @@ -61,4 +61,5 @@ wide reset, like the POR is.
>  Drawback of the PMIC solution is, you can't use the SoC's internal mechanisms to
>  detect the :ref:`reset_reason` anymore. From the SoC point of view it is always
>  a POR when the PMIC handles the system reset. If you are in luck the PMIC
> -instead can provide this information if you depend on it.
> +instead can provide this information if you depend on it. Refer
> +:ref:`reset_reason_scope` for further information.
> diff --git a/arch/arm/mach-imx/imx1.c b/arch/arm/mach-imx/imx1.c
> index 51bdcbf..a3759df 100644
> --- a/arch/arm/mach-imx/imx1.c
> +++ b/arch/arm/mach-imx/imx1.c
> @@ -18,7 +18,7 @@
>  #include <mach/weim.h>
>  #include <mach/iomux-v1.h>
>  #include <mach/generic.h>
> -#include <reset_source.h>
> +#include <restart.h>
>  
>  #define MX1_RSR MX1_SCM_BASE_ADDR
>  #define RSR_EXR	(1 << 0)
> @@ -30,13 +30,13 @@ static void imx1_detect_reset_source(void)
>  
>  	switch (val) {
>  	case RSR_EXR:
> -		reset_source_set(RESET_RST);
> +		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
>  		return;
>  	case RSR_WDR:
> -		reset_source_set(RESET_WDG);
> +		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
>  		return;
>  	case 0:
> -		reset_source_set(RESET_POR);
> +		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
>  		return;
>  	default:
>  		/* else keep the default 'unknown' state */
> diff --git a/arch/arm/mach-omap/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c
> index 7ce32f0..8ac1290 100644
> --- a/arch/arm/mach-omap/am33xx_generic.c
> +++ b/arch/arm/mach-omap/am33xx_generic.c
> @@ -26,7 +26,7 @@
>  #include <mach/sys_info.h>
>  #include <mach/am33xx-generic.h>
>  #include <mach/gpmc.h>
> -#include <reset_source.h>
> +#include <restart.h>
>  
>  void __noreturn am33xx_reset_cpu(unsigned long addr)
>  {
> @@ -167,23 +167,23 @@ static void am33xx_detect_reset_reason(void)
>  
>  	switch (val) {
>  	case (1 << 9):
> -		reset_source_set(RESET_JTAG);
> +		reset_source_set(RESET_JTAG, FEATURE_SCOPE_SOC);
>  		break;
>  	case (1 << 5):
> -		reset_source_set(RESET_EXT);
> +		reset_source_set(RESET_EXT, FEATURE_SCOPE_SOC);
>  		break;
>  	case (1 << 4):
>  	case (1 << 3):
> -		reset_source_set(RESET_WDG);
> +		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
>  		break;
>  	case (1 << 1):
> -		reset_source_set(RESET_RST);
> +		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
>  		break;
>  	case (1 << 0):
> -		reset_source_set(RESET_POR);
> +		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
>  		break;
>  	default:
> -		reset_source_set(RESET_UKWN);
> +		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
>  		break;
>  	}
>  }
> diff --git a/arch/arm/mach-pxa/pxa2xx.c b/arch/arm/mach-pxa/pxa2xx.c
> index b712b38..973e394 100644
> --- a/arch/arm/mach-pxa/pxa2xx.c
> +++ b/arch/arm/mach-pxa/pxa2xx.c
> @@ -14,7 +14,7 @@
>  
>  #include <common.h>
>  #include <init.h>
> -#include <reset_source.h>
> +#include <restart.h>
>  #include <mach/hardware.h>
>  #include <mach/pxa-regs.h>
>  
> @@ -28,15 +28,15 @@ static int pxa_detect_reset_source(void)
>  	 * Order is important, as many bits can be set together
>  	 */
>  	if (reg & RCSR_GPR)
> -		reset_source_set(RESET_RST);
> +		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
>  	else if (reg & RCSR_WDR)
> -		reset_source_set(RESET_WDG);
> +		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
>  	else if (reg & RCSR_HWR)
> -		reset_source_set(RESET_POR);
> +		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
>  	else if (reg & RCSR_SMR)
> -		reset_source_set(RESET_WKE);
> +		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
>  	else
> -		reset_source_set(RESET_UKWN);
> +		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
>  
>  	return 0;
>  }
> diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
> index 86ca63b..e273996 100644
> --- a/arch/arm/mach-pxa/pxa3xx.c
> +++ b/arch/arm/mach-pxa/pxa3xx.c
> @@ -14,7 +14,7 @@
>  
>  #include <common.h>
>  #include <init.h>
> -#include <reset_source.h>
> +#include <restart.h>
>  #include <mach/hardware.h>
>  #include <mach/pxa-regs.h>
>  
> @@ -28,15 +28,15 @@ static int pxa_detect_reset_source(void)
>  	 * Order is important, as many bits can be set together
>  	 */
>  	if (reg & ARSR_GPR)
> -		reset_source_set(RESET_RST);
> +		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
>  	else if (reg & ARSR_WDT)
> -		reset_source_set(RESET_WDG);
> +		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
>  	else if (reg & ARSR_HWR)
> -		reset_source_set(RESET_POR);
> +		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
>  	else if (reg & ARSR_LPMR)
> -		reset_source_set(RESET_WKE);
> +		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
>  	else
> -		reset_source_set(RESET_UKWN);
> +		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
>  
>  	return 0;
>  }
> diff --git a/arch/arm/mach-samsung/reset_source.c b/arch/arm/mach-samsung/reset_source.c
> index c1365b2..e122909 100644
> --- a/arch/arm/mach-samsung/reset_source.c
> +++ b/arch/arm/mach-samsung/reset_source.c
> @@ -15,7 +15,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <io.h>
> -#include <reset_source.h>
> +#include <restart.h>
>  #include <mach/s3c-iomap.h>
>  
>  /* S3C2440 relevant */
> @@ -29,21 +29,21 @@ static int s3c_detect_reset_source(void)
>  	u32 reg = readl(S3C_GPIO_BASE + S3C2440_GSTATUS2);
>  
>  	if (reg & S3C2440_GSTATUS2_PWRST) {
> -		reset_source_set(RESET_POR);
> +		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
>  		writel(S3C2440_GSTATUS2_PWRST,
>  					S3C_GPIO_BASE + S3C2440_GSTATUS2);
>  		return 0;
>  	}
>  
>  	if (reg & S3C2440_GSTATUS2_SLEEPRST) {
> -		reset_source_set(RESET_WKE);
> +		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
>  		writel(S3C2440_GSTATUS2_SLEEPRST,
>  					S3C_GPIO_BASE + S3C2440_GSTATUS2);
>  		return 0;
>  	}
>  
>  	if (reg & S3C2440_GSTATUS2_WDRST) {
> -		reset_source_set(RESET_WDG);
> +		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
>  		writel(S3C2440_GSTATUS2_WDRST,
>  					S3C_GPIO_BASE + S3C2440_GSTATUS2);
>  		return 0;
> diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c
> index eaa5ac7..6493eea 100644
> --- a/arch/arm/mach-tegra/tegra20-pmc.c
> +++ b/arch/arm/mach-tegra/tegra20-pmc.c
> @@ -28,7 +28,7 @@
>  #include <linux/reset.h>
>  #include <mach/lowlevel.h>
>  #include <mach/tegra-powergate.h>
> -#include <reset_source.h>
> +#include <restart.h>
>  
>  #include <mach/tegra20-pmc.h>
>  
> @@ -180,22 +180,22 @@ static void tegra20_pmc_detect_reset_cause(void)
>  	switch ((reg & PMC_RST_STATUS_RST_SRC_MASK) >>
>  	         PMC_RST_STATUS_RST_SRC_SHIFT) {
>  	case PMC_RST_STATUS_RST_SRC_POR:
> -		reset_source_set(RESET_POR);
> +		reset_source_set(RESET_POR, FEATURE_SCOPE_SOC);
>  		break;
>  	case PMC_RST_STATUS_RST_SRC_WATCHDOG:
> -		reset_source_set(RESET_WDG);
> +		reset_source_set(RESET_WDG, FEATURE_SCOPE_SOC);
>  		break;
>  	case PMC_RST_STATUS_RST_SRC_LP0:
> -		reset_source_set(RESET_WKE);
> +		reset_source_set(RESET_WKE, FEATURE_SCOPE_SOC);
>  		break;
>  	case PMC_RST_STATUS_RST_SRC_SW_MAIN:
> -		reset_source_set(RESET_RST);
> +		reset_source_set(RESET_RST, FEATURE_SCOPE_SOC);
>  		break;
>  	case PMC_RST_STATUS_RST_SRC_SENSOR:
> -		reset_source_set(RESET_THERM);
> +		reset_source_set(RESET_THERM, FEATURE_SCOPE_SOC);
>  		break;
>  	default:
> -		reset_source_set(RESET_UKWN);
> +		reset_source_set(RESET_UKWN, FEATURE_SCOPE_SOC);
>  		break;
>  	}
>  }
> diff --git a/common/Kconfig b/common/Kconfig
> index 3dfb5ac..f241482 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -716,14 +716,6 @@ config STATE
>  	select OFTREE
>  	select PARAMETER
>  
> -config RESET_SOURCE
> -	bool "detect Reset cause"
> -	depends on GLOBALVAR
> -	help
> -	  Provide a global variable at runtine which reflects the possible cause
> -	  of the reset and why the bootloader is currently running. It can be
> -	  useful for any kind of system recovery or repair.
> -
>  endmenu
>  
>  menu "Debugging"
> diff --git a/common/Makefile b/common/Makefile
> index 2738238..16e6690 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -8,6 +8,7 @@ obj-y				+= misc.o
>  obj-y				+= memsize.o
>  obj-y				+= resource.o
>  obj-y				+= bootsource.o
> +obj-y				+= restart.o
>  obj-$(CONFIG_AUTO_COMPLETE)	+= complete.o
>  obj-$(CONFIG_BANNER)		+= version.o
>  obj-$(CONFIG_BAREBOX_UPDATE)	+= bbu.o
> @@ -40,7 +41,6 @@ obj-$(CONFIG_OFTREE)		+= oftree.o
>  obj-$(CONFIG_PARTITION_DISK)	+= partitions.o partitions/
>  obj-$(CONFIG_PASSWORD)		+= password.o
>  obj-$(CONFIG_POLLER)		+= poller.o
> -obj-$(CONFIG_RESET_SOURCE)	+= reset_source.o
>  obj-$(CONFIG_SHELL_HUSH)	+= hush.o
>  obj-$(CONFIG_SHELL_SIMPLE)	+= parser.o
>  obj-$(CONFIG_STATE)		+= state.o
> diff --git a/common/reset_source.c b/common/reset_source.c
> deleted file mode 100644
> index 80002a9..0000000
> --- a/common/reset_source.c
> +++ /dev/null
> @@ -1,56 +0,0 @@
> -/*
> - * (C) Copyright 2012 Juergen Beisert - <kernel@pengutronix.de>
> - *
> - * 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 <common.h>
> -#include <init.h>
> -#include <environment.h>
> -#include <globalvar.h>
> -#include <reset_source.h>
> -
> -static const char * const reset_src_names[] = {
> -	[RESET_UKWN] = "unknown",
> -	[RESET_POR] = "POR",
> -	[RESET_RST] = "RST",
> -	[RESET_WDG] = "WDG",
> -	[RESET_WKE] = "WKE",
> -	[RESET_JTAG] = "JTAG",
> -	[RESET_THERM] = "THERM",
> -	[RESET_EXT] = "EXT",
> -};
> -
> -static enum reset_src_type reset_source;
> -
> -enum reset_src_type reset_source_get(void)
> -{
> -	return reset_source;
> -}
> -EXPORT_SYMBOL(reset_source_get);
> -
> -void reset_source_set(enum reset_src_type st)
> -{
> -	reset_source = st;
> -
> -	globalvar_add_simple("system.reset", reset_src_names[reset_source]);
> -}
> -EXPORT_SYMBOL(reset_source_set);
> -
> -/* ensure this runs after the 'global' device is already registerd */
> -static int reset_source_init(void)
> -{
> -	reset_source_set(reset_source);
> -
> -	return 0;
> -}
> -
> -coredevice_initcall(reset_source_init);
> diff --git a/common/restart.c b/common/restart.c
> new file mode 100644
> index 0000000..f73a9da
> --- /dev/null
> +++ b/common/restart.c
> @@ -0,0 +1,73 @@
> +/*
> + * (C) Copyright 2015 Juergen Borleis - <kernel@pengutronix.de>
> + *
> + * 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 <common.h>
> +#include <init.h>
> +#include <restart.h>
> +#include <globalvar.h>
> +
> +static const char * const scope_names[] = {
> +	[FEATURE_SCOPE_UNKNOWN] = "unknown",
> +	[FEATURE_SCOPE_CPU] = "cpu",
> +	[FEATURE_SCOPE_SOC] = "soc",
> +	[FEATURE_SCOPE_MACHINE] = "machine",
> +};
> +
> +static const char * const reset_src_names[] = {
> +	[RESET_UKWN] = "unknown",
> +	[RESET_POR] = "POR",
> +	[RESET_RST] = "RST",
> +	[RESET_WDG] = "WDG",
> +	[RESET_WKE] = "WKE",
> +	[RESET_JTAG] = "JTAG",
> +	[RESET_THERM] = "THERM",
> +	[RESET_EXT] = "EXT",
> +};
> +
> +/* handle reset cause detection feature */
> +
> +static int reset_source;
> +static int reset_source_scope;
> +
> +enum reset_src_type reset_source_get(void)
> +{
> +	return reset_source;
> +}
> +EXPORT_SYMBOL(reset_source_get);
> +
> +static void reset_source_update_global_info(void)
> +{
> +	globalvar_add_simple_enum("system.reset", &reset_source, reset_src_names,
> +					ARRAY_SIZE(reset_src_names));
> +	globalvar_add_simple_enum("system.reset.scope", &reset_source_scope,
> +					scope_names, ARRAY_SIZE(scope_names));
> +}
> +
> +void reset_source_set(enum reset_src_type st, enum f_scope scope)
> +{
> +	if ((int)scope <= reset_source_scope)
> +		return; /* just ignore this setting */
> +
> +	reset_source = (int)st;
> +	reset_source_scope = (int)scope;
> +	reset_source_update_global_info();

This call is unnecessary. You can call globalvar_add_simple_enum()
directly from the initcall.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] System restart: add a scope value to the system restart feature
  2015-06-23 12:58 ` [PATCH 2/5] System restart: add a scope value to the system restart feature Juergen Borleis
@ 2015-06-24  6:42   ` Sascha Hauer
  0 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-24  6:42 UTC (permalink / raw)
  To: Juergen Borleis; +Cc: barebox

On Tue, Jun 23, 2015 at 02:58:01PM +0200, Juergen Borleis wrote:
> Some systems have more than one feature to restart it. Maybe these restarts
> features are all equal or it is very important which restart feauture is used
> to restart the system in a reliable manner. For example if external
> devices must be reset in conjunction with the SoC some SoC's internal
> restart features cannot be used. Then an external restart feature must
> be forced instead by using the restart feature with the wider scope.
> 
> Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
> ---
>  Documentation/user/system-reset.rst              | 41 ++++++++++++++++++
>  arch/arm/lib/bootm.c                             |  7 +--
>  arch/arm/mach-at91/at91rm9200_time.c             | 12 ++++--
>  arch/arm/mach-bcm2835/core.c                     | 21 ++++-----
>  arch/arm/mach-clps711x/reset.c                   | 10 ++++-
>  arch/arm/mach-davinci/time.c                     | 12 ++++--
>  arch/arm/mach-digic/core.c                       | 25 -----------
>  arch/arm/mach-ep93xx/clocksource.c               | 17 +++++---
>  arch/arm/mach-highbank/reset.c                   | 12 +++++-
>  arch/arm/mach-mvebu/armada-370-xp.c              |  9 ++--
>  arch/arm/mach-mvebu/common.c                     | 13 ------
>  arch/arm/mach-mvebu/dove.c                       |  9 ++--
>  arch/arm/mach-mvebu/include/mach/common.h        |  1 -
>  arch/arm/mach-mvebu/kirkwood.c                   |  9 ++--
>  arch/arm/mach-mxs/soc-imx23.c                    |  8 ++--
>  arch/arm/mach-mxs/soc-imx28.c                    | 13 ++++--
>  arch/arm/mach-netx/generic.c                     | 11 ++++-
>  arch/arm/mach-nomadik/reset.c                    | 13 ++++--
>  arch/arm/mach-omap/am33xx_generic.c              |  4 +-
>  arch/arm/mach-omap/include/mach/am33xx-generic.h |  2 +-
>  arch/arm/mach-omap/include/mach/omap3-generic.h  |  2 +-
>  arch/arm/mach-omap/include/mach/omap4-generic.h  |  2 +-
>  arch/arm/mach-omap/omap3_generic.c               |  5 +--
>  arch/arm/mach-omap/omap4_generic.c               |  4 +-
>  arch/arm/mach-omap/omap_generic.c                | 12 +++---
>  arch/arm/mach-pxa/common.c                       | 12 +++++-
>  arch/arm/mach-rockchip/core.c                    | 14 ++++--
>  arch/arm/mach-samsung/generic.c                  | 13 ++++--
>  arch/arm/mach-socfpga/reset-manager.c            | 12 +++++-
>  arch/arm/mach-tegra/tegra20-pmc.c                |  6 +--
>  arch/arm/mach-uemd/reset.c                       | 24 -----------
>  arch/arm/mach-versatile/core.c                   |  7 +--
>  arch/arm/mach-vexpress/reset.c                   | 13 ++++--
>  arch/arm/mach-zynq/zynq.c                        | 12 ++++--
>  arch/blackfin/lib/cpu.c                          | 11 ++++-
>  arch/efi/efi/efi.c                               | 11 ++++-
>  arch/mips/mach-ar231x/ar231x_reset.c             |  8 ++--
>  arch/mips/mach-ath79/reset.c                     | 13 ++++--
>  arch/mips/mach-bcm47xx/reset.c                   | 14 ++++--
>  arch/mips/mach-loongson/loongson1_reset.c        | 13 ++++--
>  arch/mips/mach-malta/reset.c                     | 14 ++++--
>  arch/nios2/cpu/cpu.c                             | 12 +++++-
>  arch/openrisc/cpu/cpu.c                          | 11 ++++-
>  arch/ppc/mach-mpc5xxx/cpu.c                      | 11 ++++-
>  arch/ppc/mach-mpc85xx/cpu.c                      | 12 ++++--
>  arch/sandbox/os/common.c                         | 10 ++++-
>  arch/x86/mach-i386/reset.c                       | 30 -------------
>  commands/reset.c                                 |  3 +-
>  common/misc.c                                    |  3 +-
>  common/restart.c                                 | 55 ++++++++++++++++++++++++
>  drivers/usb/gadget/f_fastboot.c                  |  3 +-
>  drivers/watchdog/imxwd.c                         | 21 ++++-----
>  drivers/watchdog/jz4740.c                        | 33 ++++++--------
>  include/common.h                                 |  1 -
>  include/restart.h                                |  6 +++
>  55 files changed, 432 insertions(+), 250 deletions(-)
>  delete mode 100644 arch/arm/mach-digic/core.c
>  delete mode 100644 arch/arm/mach-uemd/reset.c
>  delete mode 100644 arch/x86/mach-i386/reset.c
> 
> diff --git a/Documentation/user/system-reset.rst b/Documentation/user/system-reset.rst
> index e902026..6770371 100644
> --- a/Documentation/user/system-reset.rst
> +++ b/Documentation/user/system-reset.rst
> @@ -3,6 +3,11 @@
>  System Restart
>  --------------
>  
> +.. _system_reset_pitfalls:
> +
> +Common Pitfalls
> +~~~~~~~~~~~~~~~
> +
>  When running the reset command barebox restarts the SoC somehow. Restart can
>  be done in software, but a more reliable way is to use a hard reset line, which
>  really resets the whole machine.
> @@ -63,3 +68,39 @@ detect the :ref:`reset_reason` anymore. From the SoC point of view it is always
>  a POR when the PMIC handles the system reset. If you are in luck the PMIC
>  instead can provide this information if you depend on it. Refer
>  :ref:`reset_reason_scope` for further information.
> +
> +Handling the system restart from the developers point of view
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Sometimes more than one system restart feature is available on a machine and
> +due to 'some reasons' all these unit's drivers must be enabled at run-time
> +(maybe they are MFDs (e.g. multi function devices) or you want to run one
> +binary barebox on more than one machine). In such a case more than one driver
> +registers its system reset feature at run-time. So a mechanism is required
> +in order to let barebox selects the 'correct' one to trigger a system restart.
> +
> +Barebox can handle and use one system restart feature only. If the available
> +system restart features are equivalent it doesn't matter which one barebox
> +selects to trigger a system restart. But if your machine depends on a specific
> +system restart feature you must ensure it will be used all the time to get a
> +reliable system restart.
> +
> +To handle this, registering system restart features are handled by their scope.
> +Due to the listed issues in :ref:`system_reset_pitfalls` all the (mostly) built-in
> +watchdog units will register their system restart feature with a limited scope.
> +And will still be used by barebox to restart the system if no alternative is
> +available.
> +If your machine has special requirements to restart the system and a more reliable
> +system restart feature is on hand it must register its system restart feature
> +with a wider scope. Barebox will then prefer the wider scope feature to restart
> +the system.
> +
> +Here the list of defined scopes (defined in file ``include/restart.h``):
> +
> +* ``FEATURE_SCOPE_UNKNOWN``: last resort to restart a machine and might be used
> +  as a fall-back only.
> +* ``FEATURE_SCOPE_CPU``: this restart feature is able to restart the core CPU only.
> +* ``FEATURE_SCOPE_SOC``: this restart feature is able to restart the whole SoC,
> +  including the core CPU.
> +* ``FEATURE_SCOPE_MACHINE``: this restart feature is able to restart the whole machine,
> +  including the SoC and the core CPU.
> diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
> index 8327c3f..7bb9b43 100644
> --- a/arch/arm/lib/bootm.c
> +++ b/arch/arm/lib/bootm.c
> @@ -16,6 +16,7 @@
>  #include <libbb.h>
>  #include <magicvar.h>
>  #include <binfmt.h>
> +#include <restart.h>
>  
>  #include <asm/byteorder.h>
>  #include <asm/setup.h>
> @@ -111,7 +112,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int
>  
>  	start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree);
>  
> -	reset_cpu(0);
> +	restart_machine();
>  
>  	return -ERESTARTSYS;
>  }
> @@ -378,7 +379,7 @@ static int do_bootm_barebox(struct image_data *data)
>  
>  	start_linux(barebox, 0, 0, 0, data->oftree);
>  
> -	reset_cpu(0);
> +	restart_machine();
>  }
>  
>  static struct image_handler barebox_handler = {
> @@ -518,7 +519,7 @@ static int do_bootm_aimage(struct image_data *data)
>  
>  		second();
>  
> -		reset_cpu(0);
> +		restart_machine();
>  	}
>  
>  	close(fd);
> diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
> index ae0172b..c017ad8 100644
> --- a/arch/arm/mach-at91/at91rm9200_time.c
> +++ b/arch/arm/mach-at91/at91rm9200_time.c
> @@ -28,6 +28,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <clock.h>
> +#include <restart.h>
>  #include <mach/hardware.h>
>  #include <mach/at91_tc.h>
>  #include <mach/at91_st.h>
> @@ -77,7 +78,7 @@ core_initcall(clocksource_init);
>  /*
>   * Reset the cpu through the reset controller
>   */
> -void __noreturn reset_cpu (unsigned long ignored)
> +static void __noreturn at91rm9200_restart_soc(struct device_d *dev)
>  {
>  	/*
>  	 * Perform a hardware reset with the use of the Watchdog timer.
> @@ -86,6 +87,11 @@ void __noreturn reset_cpu (unsigned long ignored)
>  	at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
>  
>  	/* Not reached */
> -	while (1);
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(at91rm9200_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-bcm2835/core.c b/arch/arm/mach-bcm2835/core.c
> index 5d08012..6f6ae8a 100644
> --- a/arch/arm/mach-bcm2835/core.c
> +++ b/arch/arm/mach-bcm2835/core.c
> @@ -18,6 +18,7 @@
>  
>  #include <common.h>
>  #include <init.h>
> +#include <restart.h>
>  
>  #include <linux/clk.h>
>  #include <linux/clkdev.h>
> @@ -51,13 +52,6 @@ static int bcm2835_clk_init(void)
>  }
>  postcore_initcall(bcm2835_clk_init);
>  
> -static int bcm2835_dev_init(void)
> -{
> -	add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL);
> -	return 0;
> -}
> -coredevice_initcall(bcm2835_dev_init);
> -
>  void bcm2835_register_uart(void)
>  {
>  	amba_apb_device_add(NULL, "uart0-pl011", 0, BCM2835_UART0_BASE, 4096, NULL, 0);
> @@ -72,7 +66,7 @@ void bcm2835_add_device_sdram(u32 size)
>  }
>  #define RESET_TIMEOUT 10
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn bcm2835_restart_soc(struct device_d *dev)
>  {
>  	uint32_t rstc;
>  
> @@ -82,6 +76,13 @@ void __noreturn reset_cpu(unsigned long addr)
>  	writel(PM_PASSWORD | RESET_TIMEOUT, PM_WDOG);
>  	writel(PM_PASSWORD | rstc, PM_RSTC);
>  
> -	while (1);
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int bcm2835_dev_init(void)
> +{
> +	add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL);
> +	restart_register_handler(bcm2835_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +	return 0;
> +}
> +coredevice_initcall(bcm2835_dev_init);
> diff --git a/arch/arm/mach-clps711x/reset.c b/arch/arm/mach-clps711x/reset.c
> index 67c9c8b..225ef15 100644
> --- a/arch/arm/mach-clps711x/reset.c
> +++ b/arch/arm/mach-clps711x/reset.c
> @@ -8,8 +8,10 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
> +#include <restart.h>
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn clps711x_restart_soc(struct device_d *dev)
>  {
>  	arch_shutdown();
>  
> @@ -17,3 +19,9 @@ void __noreturn reset_cpu(unsigned long addr)
>  
>  	hang();
>  }
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(clps711x_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
> index 60f0d19..8b53879 100644
> --- a/arch/arm/mach-davinci/time.c
> +++ b/arch/arm/mach-davinci/time.c
> @@ -12,6 +12,7 @@
>  #include <common.h>
>  #include <io.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <clock.h>
>  
>  #include <mach/time.h>
> @@ -164,7 +165,7 @@ static int clocksource_init(void)
>  core_initcall(clocksource_init);
>  
>  /* reset board using watchdog timer */
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn davinci_restart_soc(struct device_d *dev)
>  {
>  	u32 tgcr, wdtcr;
>  	void __iomem *base;
> @@ -204,6 +205,11 @@ void __noreturn reset_cpu(ulong addr)
>  	wdtcr = 0x00004000;
>  	__raw_writel(wdtcr, base + WDTCR);
>  
> -	unreachable();
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(davinci_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-digic/core.c b/arch/arm/mach-digic/core.c
> deleted file mode 100644
> index b1caec0..0000000
> --- a/arch/arm/mach-digic/core.c
> +++ /dev/null
> @@ -1,25 +0,0 @@
> -/*
> - * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
> - *
> - * This file is part of barebox.
> - * See file CREDITS for list of people who contributed to this project.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2
> - * as published by the Free Software Foundation.
> - *
> - * 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 <common.h>
> -
> -void __noreturn reset_cpu(unsigned long ignored)
> -{
> -	pr_err("%s: unimplemented\n", __func__);
> -	hang();
> -}
> -EXPORT_SYMBOL(reset_cpu);
> diff --git a/arch/arm/mach-ep93xx/clocksource.c b/arch/arm/mach-ep93xx/clocksource.c
> index f396d0a..c811641 100644
> --- a/arch/arm/mach-ep93xx/clocksource.c
> +++ b/arch/arm/mach-ep93xx/clocksource.c
> @@ -20,6 +20,7 @@
>  #include <init.h>
>  #include <clock.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <mach/ep93xx-regs.h>
>  
>  #define TIMER_CLKSEL		(1 << 3)
> @@ -63,10 +64,8 @@ static int clocksource_init(void)
>  
>  core_initcall(clocksource_init);
>  
> -/*
> - * Reset the cpu
> - */
> -void __noreturn reset_cpu(unsigned long addr)
> +/* Reset the SoC */
> +static void __noreturn ep92xx_restart_soc(struct device_d *dev)
>  {
>  	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE;
>  	uint32_t value;
> @@ -84,7 +83,11 @@ void __noreturn reset_cpu(unsigned long addr)
>  	writel(value, &syscon->devicecfg);
>  
>  	/* Dying... */
> -	while (1)
> -		; /* noop */
> +	hang();
> +}
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(ep92xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-highbank/reset.c b/arch/arm/mach-highbank/reset.c
> index b9664e4..cff5cae 100644
> --- a/arch/arm/mach-highbank/reset.c
> +++ b/arch/arm/mach-highbank/reset.c
> @@ -6,17 +6,25 @@
>  
>  #include <common.h>
>  #include <io.h>
> +#include <restart.h>
> +#include <init.h>
>  
>  #include <mach/devices.h>
>  #include <mach/sysregs.h>
>  
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn highbank_restart_soc(struct device_d *dev)
>  {
>  	hingbank_set_pwr_hard_reset();
>  	asm("	wfi");
>  
> -	while(1);
> +	hang();
> +}
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(highbank_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  }
> +coredevice_initcall(restart_register_feature);
>  
>  void __noreturn poweroff()
>  {
> diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
> index 2405629..0c52523 100644
> --- a/arch/arm/mach-mvebu/armada-370-xp.c
> +++ b/arch/arm/mach-mvebu/armada-370-xp.c
> @@ -17,6 +17,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <of.h>
>  #include <of_address.h>
>  #include <asm/memory.h>
> @@ -104,12 +105,12 @@ static int armada_370_xp_soc_id_fixup(void)
>  	return 0;
>  }
>  
> -static void __noreturn armada_370_xp_reset_cpu(unsigned long addr)
> +static void __noreturn armada_370_xp_restart_soc(struct device_d *dev)
>  {
>  	writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x60);
>  	writel(0x1, ARMADA_370_XP_SYSCTL_BASE + 0x64);
> -	while (1)
> -		;
> +
> +	hang();
>  }
>  
>  static int armada_xp_init_soc(struct device_node *root)
> @@ -132,7 +133,7 @@ static int armada_370_xp_init_soc(struct device_node *root, void *context)
>  	if (!of_machine_is_compatible("marvell,armada-370-xp"))
>  		return 0;
>  
> -	mvebu_set_reset(armada_370_xp_reset_cpu);
> +	restart_register_handler(armada_370_xp_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  
>  	barebox_set_model("Marvell Armada 370/XP");
>  	barebox_set_hostname("armada");
> diff --git a/arch/arm/mach-mvebu/common.c b/arch/arm/mach-mvebu/common.c
> index 7d28d9c..cb40d0c 100644
> --- a/arch/arm/mach-mvebu/common.c
> +++ b/arch/arm/mach-mvebu/common.c
> @@ -123,16 +123,3 @@ int mvebu_set_memory(u64 phys_base, u64 phys_size)
>  
>  	return 0;
>  }
> -
> -static __noreturn void (*mvebu_reset_cpu)(unsigned long addr);
> -
> -void __noreturn reset_cpu(unsigned long addr)
> -{
> -	mvebu_reset_cpu(addr);
> -}
> -EXPORT_SYMBOL(reset_cpu);
> -
> -void mvebu_set_reset(void __noreturn (*reset)(unsigned long addr))
> -{
> -	mvebu_reset_cpu = reset;
> -}
> diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c
> index a7284fd..b727215 100644
> --- a/arch/arm/mach-mvebu/dove.c
> +++ b/arch/arm/mach-mvebu/dove.c
> @@ -17,6 +17,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <asm/memory.h>
>  #include <linux/mbus.h>
>  #include <mach/dove-regs.h>
> @@ -68,13 +69,13 @@ static inline void dove_memory_find(unsigned long *phys_base,
>  	}
>  }
>  
> -static void __noreturn dove_reset_cpu(unsigned long addr)
> +static void __noreturn dove_restart_soc(struct device_d *dev)
>  {
>  	/* enable and assert RSTOUTn */
>  	writel(SOFT_RESET_OUT_EN, DOVE_BRIDGE_BASE + BRIDGE_RSTOUT_MASK);
>  	writel(SOFT_RESET_EN, DOVE_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET);
> -	while (1)
> -		;
> +
> +	hang();
>  }
>  
>  static int dove_init_soc(struct device_node *root, void *context)
> @@ -84,7 +85,7 @@ static int dove_init_soc(struct device_node *root, void *context)
>  	if (!of_machine_is_compatible("marvell,dove"))
>  		return 0;
>  
> -	mvebu_set_reset(dove_reset_cpu);
> +	restart_register_handler(dove_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  
>  	barebox_set_model("Marvell Dove");
>  	barebox_set_hostname("dove");
> diff --git a/arch/arm/mach-mvebu/include/mach/common.h b/arch/arm/mach-mvebu/include/mach/common.h
> index 5ce33fd..602af8f 100644
> --- a/arch/arm/mach-mvebu/include/mach/common.h
> +++ b/arch/arm/mach-mvebu/include/mach/common.h
> @@ -21,6 +21,5 @@
>  #define MVEBU_REMAP_INT_REG_BASE	0xf1000000
>  
>  int mvebu_set_memory(u64 phys_base, u64 phys_size);
> -void mvebu_set_reset(void __noreturn (*reset)(unsigned long addr));
>  
>  #endif
> diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c
> index 19c6f07..00e213f 100644
> --- a/arch/arm/mach-mvebu/kirkwood.c
> +++ b/arch/arm/mach-mvebu/kirkwood.c
> @@ -16,6 +16,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <asm/memory.h>
>  #include <linux/mbus.h>
>  #include <mach/kirkwood-regs.h>
> @@ -43,12 +44,12 @@ static inline void kirkwood_memory_find(unsigned long *phys_base,
>  	}
>  }
>  
> -static void __noreturn kirkwood_reset_cpu(unsigned long addr)
> +static void __noreturn kirkwood_restart_soc(struct device_d *dev)
>  {
>  	writel(SOFT_RESET_OUT_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_RSTOUT_MASK);
>  	writel(SOFT_RESET_EN, KIRKWOOD_BRIDGE_BASE + BRIDGE_SYS_SOFT_RESET);
> -	for(;;)
> -		;
> +
> +	hang();
>  }
>  
>  static int kirkwood_init_soc(struct device_node *root, void *context)
> @@ -58,7 +59,7 @@ static int kirkwood_init_soc(struct device_node *root, void *context)
>  	if (!of_machine_is_compatible("marvell,kirkwood"))
>  		return 0;
>  
> -	mvebu_set_reset(kirkwood_reset_cpu);
> +	restart_register_handler(kirkwood_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  
>  	barebox_set_model("Marvell Kirkwood");
>  	barebox_set_hostname("kirkwood");
> diff --git a/arch/arm/mach-mxs/soc-imx23.c b/arch/arm/mach-mxs/soc-imx23.c
> index 339c577..fd8cf04 100644
> --- a/arch/arm/mach-mxs/soc-imx23.c
> +++ b/arch/arm/mach-mxs/soc-imx23.c
> @@ -16,6 +16,7 @@
>  
>  #include <common.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <mach/imx23-regs.h>
>  #include <io.h>
>  
> @@ -23,18 +24,16 @@
>  # define HW_CLKCTRL_RESET_CHIP (1 << 1)
>  
>  /* Reset the full i.MX23 SoC via a chipset feature */
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn imx23_restart_soc(struct device_d *dev)
>  {
>  	u32 reg;
>  
>  	reg = readl(IMX_CCM_BASE + HW_CLKCTRL_RESET);
>  	writel(reg | HW_CLKCTRL_RESET_CHIP, IMX_CCM_BASE + HW_CLKCTRL_RESET);
>  
> -	while (1)
> -		;
> +	hang();
>  	/*NOTREACHED*/
>  }
> -EXPORT_SYMBOL(reset_cpu);
>  
>  static int imx23_devices_init(void)
>  {
> @@ -46,6 +45,7 @@ static int imx23_devices_init(void)
>  	add_generic_device("imx23-gpio", 0, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL);
>  	add_generic_device("imx23-gpio", 1, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL);
>  	add_generic_device("imx23-gpio", 2, NULL, IMX_IOMUXC_BASE, 0x2000, IORESOURCE_MEM, NULL);
> +	restart_register_handler(imx23_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  
>  	return 0;
>  }
> diff --git a/arch/arm/mach-mxs/soc-imx28.c b/arch/arm/mach-mxs/soc-imx28.c
> index b4ec38d..ed9ae05 100644
> --- a/arch/arm/mach-mxs/soc-imx28.c
> +++ b/arch/arm/mach-mxs/soc-imx28.c
> @@ -16,6 +16,7 @@
>  
>  #include <common.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <mach/imx28-regs.h>
>  #include <io.h>
>  
> @@ -24,18 +25,22 @@
>  #define HW_CLKCTRL_WDOG_POR_DISABLE (1 << 5)
>  
>  /* Reset the full i.MX28 SoC via a chipset feature */
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn imx28_restart_soc(struct device_d *dev)
>  {
>  	u32 reg;
>  
>  	reg = readl(IMX_CCM_BASE + HW_CLKCTRL_RESET);
>  	writel(reg | HW_CLKCTRL_RESET_CHIP, IMX_CCM_BASE + HW_CLKCTRL_RESET);
>  
> -	while (1)
> -		;
> +	hang();
>  	/*NOTREACHED*/
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(imx28_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
>  
>  static int imx28_init(void)
>  {
> diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
> index 6127dde..7ae1b4c 100644
> --- a/arch/arm/mach-netx/generic.c
> +++ b/arch/arm/mach-netx/generic.c
> @@ -15,8 +15,10 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
>  #include <command.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <mach/netx-regs.h>
>  #include "eth_firmware.h"
>  
> @@ -134,14 +136,19 @@ failure:
>  	return COMMAND_ERROR_USAGE;
>  }
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn netx_restart_soc(struct device_d *dev)
>  {
>  	SYSTEM_REG(SYSTEM_RES_CR) = 0x01000008;
>  
>  	/* Not reached */
> -	while (1);
> +	hang();
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(netx_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
>  
>  BAREBOX_CMD_START(loadxc)
>  	.cmd		= do_loadxc,
> diff --git a/arch/arm/mach-nomadik/reset.c b/arch/arm/mach-nomadik/reset.c
> index bb5696a..fa9f650 100644
> --- a/arch/arm/mach-nomadik/reset.c
> +++ b/arch/arm/mach-nomadik/reset.c
> @@ -15,10 +15,12 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <mach/hardware.h>
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn nomadik_restart_soc(struct device_d *dev)
>  {
>  	void __iomem *src_rstsr = (void *)(NOMADIK_SRC_BASE + 0x18);
>  
> @@ -28,6 +30,11 @@ void __noreturn reset_cpu(unsigned long addr)
>  	writel(1, src_rstsr);
>  
>  	/* Not reached */
> -	while (1);
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(nomadik_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-omap/am33xx_generic.c b/arch/arm/mach-omap/am33xx_generic.c
> index 8ac1290..2bdb569 100644
> --- a/arch/arm/mach-omap/am33xx_generic.c
> +++ b/arch/arm/mach-omap/am33xx_generic.c
> @@ -28,11 +28,11 @@
>  #include <mach/gpmc.h>
>  #include <restart.h>
>  
> -void __noreturn am33xx_reset_cpu(unsigned long addr)
> +void __noreturn am33xx_restart_soc(struct device_d *dev)
>  {
>  	writel(AM33XX_PRM_RSTCTRL_RESET, AM33XX_PRM_RSTCTRL);
>  
> -	while (1);
> +	hang();
>  }
>  
>  /**
> diff --git a/arch/arm/mach-omap/include/mach/am33xx-generic.h b/arch/arm/mach-omap/include/mach/am33xx-generic.h
> index 03418b0..22e2647 100644
> --- a/arch/arm/mach-omap/include/mach/am33xx-generic.h
> +++ b/arch/arm/mach-omap/include/mach/am33xx-generic.h
> @@ -28,7 +28,7 @@ u32 am33xx_running_in_flash(void);
>  u32 am33xx_running_in_sram(void);
>  u32 am33xx_running_in_sdram(void);
>  
> -void __noreturn am33xx_reset_cpu(unsigned long addr);
> +void __noreturn am33xx_restart_soc(struct device_d *dev);
>  
>  void am33xx_enable_per_clocks(void);
>  int am33xx_init(void);
> diff --git a/arch/arm/mach-omap/include/mach/omap3-generic.h b/arch/arm/mach-omap/include/mach/omap3-generic.h
> index 7db0838..945fe25 100644
> --- a/arch/arm/mach-omap/include/mach/omap3-generic.h
> +++ b/arch/arm/mach-omap/include/mach/omap3-generic.h
> @@ -24,7 +24,7 @@ u32 omap3_running_in_flash(void);
>  u32 omap3_running_in_sram(void);
>  u32 omap3_running_in_sdram(void);
>  
> -void __noreturn omap3_reset_cpu(unsigned long addr);
> +void __noreturn omap3_restart_soc(struct device_d *dev);
>  
>  int omap3_init(void);
>  int omap3_devices_init(void);
> diff --git a/arch/arm/mach-omap/include/mach/omap4-generic.h b/arch/arm/mach-omap/include/mach/omap4-generic.h
> index e246e36..dff3330 100644
> --- a/arch/arm/mach-omap/include/mach/omap4-generic.h
> +++ b/arch/arm/mach-omap/include/mach/omap4-generic.h
> @@ -18,7 +18,7 @@ static inline void omap4_save_bootinfo(uint32_t *info)
>  	memcpy((void *)OMAP44XX_SRAM_SCRATCH_SPACE, info, 3 * sizeof(uint32_t));
>  }
>  
> -void __noreturn omap4_reset_cpu(unsigned long addr);
> +void __noreturn omap4_restart_soc(struct device_d *dev);
>  
>  int omap4_init(void);
>  int omap4_devices_init(void);
> diff --git a/arch/arm/mach-omap/omap3_generic.c b/arch/arm/mach-omap/omap3_generic.c
> index dbb0b5f..88455ce 100644
> --- a/arch/arm/mach-omap/omap3_generic.c
> +++ b/arch/arm/mach-omap/omap3_generic.c
> @@ -52,13 +52,12 @@
>   *
>   * @return void
>   */
> -void __noreturn omap3_reset_cpu(unsigned long addr)
> +void __noreturn omap3_restart_soc(struct device_d *dev)
>  {
>  	writel(OMAP3_PRM_RSTCTRL_RESET, OMAP3_PRM_REG(RSTCTRL));
>  
> -	while (1);
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
>  
>  /**
>   * @brief Low level CPU type
> diff --git a/arch/arm/mach-omap/omap4_generic.c b/arch/arm/mach-omap/omap4_generic.c
> index 0b683da..2388d89 100644
> --- a/arch/arm/mach-omap/omap4_generic.c
> +++ b/arch/arm/mach-omap/omap4_generic.c
> @@ -34,11 +34,11 @@
>  #define EMIF_L3_CONFIG_VAL_SYS_10_LL_0		0x0A0000FF
>  #define EMIF_L3_CONFIG_VAL_SYS_10_MPU_3_LL_0	0x0A300000
>  
> -void __noreturn omap4_reset_cpu(unsigned long addr)
> +void __noreturn omap4_restart_soc(struct device_d *dev)
>  {
>  	writel(OMAP44XX_PRM_RSTCTRL_RESET, OMAP44XX_PRM_RSTCTRL);
>  
> -	while (1);
> +	hang;
>  }
>  
>  void omap4_set_warmboot_order(u32 *device_list)
> diff --git a/arch/arm/mach-omap/omap_generic.c b/arch/arm/mach-omap/omap_generic.c
> index 334cf8d..35f576f 100644
> --- a/arch/arm/mach-omap/omap_generic.c
> +++ b/arch/arm/mach-omap/omap_generic.c
> @@ -18,6 +18,7 @@
>  #include <boot.h>
>  #include <init.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <fs.h>
>  #include <malloc.h>
>  #include <libfile.h>
> @@ -150,16 +151,17 @@ static int omap_env_init(void)
>  late_initcall(omap_env_init);
>  #endif
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static int restart_register_feature(void)
>  {
>  	if (cpu_is_omap3())
> -		omap3_reset_cpu(addr);
> +		restart_register_handler(omap3_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  	if (cpu_is_omap4())
> -		omap4_reset_cpu(addr);
> +		restart_register_handler(omap4_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  	if (cpu_is_am33xx())
> -		am33xx_reset_cpu(addr);
> -	while (1);
> +		restart_register_handler(am33xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +	return 0;
>  }
> +coredevice_initcall(restart_register_feature);
>  
>  static int omap_soc_from_dt(void)
>  {
> diff --git a/arch/arm/mach-pxa/common.c b/arch/arm/mach-pxa/common.c
> index 2c27d81..3d6446d 100644
> --- a/arch/arm/mach-pxa/common.c
> +++ b/arch/arm/mach-pxa/common.c
> @@ -16,6 +16,8 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/pxa-regs.h>
>  #include <asm/io.h>
>  
> @@ -29,7 +31,7 @@
>  
>  extern void pxa_clear_reset_source(void);
>  
> -void reset_cpu(ulong addr)
> +static void __noreturn pxa_restart_soc(struct device_d *dev)
>  {
>  	/* Clear last reset source */
>  	pxa_clear_reset_source();
> @@ -39,5 +41,11 @@ void reset_cpu(ulong addr)
>  	writel(OSSR_M3, OSSR);
>  	writel(readl(OSCR) + 368640, OSMR3);  /* ... in 100 ms */
>  
> -	while (1);
> +	hang();
>  }
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(pxa_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-rockchip/core.c b/arch/arm/mach-rockchip/core.c
> index bab06df..f59d3d2 100644
> --- a/arch/arm/mach-rockchip/core.c
> +++ b/arch/arm/mach-rockchip/core.c
> @@ -13,16 +13,22 @@
>  
>  #include <asm/io.h>
>  #include <common.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/rockchip-regs.h>
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn rockchip_restart_soc(struct device_d *dev)
>  {
>  	/* Map bootrom from address 0 */
>  	writel(RK_SOC_CON0_REMAP << 16, RK_GRF_BASE + RK_GRF_SOC_CON0);
>  	/* Reset */
>  	writel(0xeca8, RK_CRU_BASE + RK_CRU_GLB_SRST_SND);
>  
> -	while (1)
> -		;
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(rockchip_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-samsung/generic.c b/arch/arm/mach-samsung/generic.c
> index 75965d7..7f7bc36 100644
> --- a/arch/arm/mach-samsung/generic.c
> +++ b/arch/arm/mach-samsung/generic.c
> @@ -21,6 +21,7 @@
>  #include <config.h>
>  #include <common.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <io.h>
>  #include <mach/s3c-iomap.h>
>  #include <mach/s3c-generic.h>
> @@ -29,7 +30,7 @@
>  #define S3C_WTDAT (S3C_WATCHDOG_BASE + 0x04)
>  #define S3C_WTCNT (S3C_WATCHDOG_BASE + 0x08)
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn samsung_restart_soc(struct device_d *dev)
>  {
>  	/* Disable watchdog */
>  	writew(0x0000, S3C_WTCON);
> @@ -41,7 +42,11 @@ void __noreturn reset_cpu(unsigned long addr)
>  	writew(0x0021, S3C_WTCON);
>  
>  	/* loop forever and wait for reset to happen */
> -	while(1)
> -		;
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(samsung_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-socfpga/reset-manager.c b/arch/arm/mach-socfpga/reset-manager.c
> index a9e7e14..eca1ee3 100644
> --- a/arch/arm/mach-socfpga/reset-manager.c
> +++ b/arch/arm/mach-socfpga/reset-manager.c
> @@ -17,6 +17,8 @@
>  
>  #include <common.h>
>  #include <io.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/socfpga-regs.h>
>  #include <mach/reset-manager.h>
>  
> @@ -38,7 +40,7 @@ void watchdog_disable(void)
>  }
>  
>  /* Write the reset manager register to cause reset */
> -void reset_cpu(ulong addr)
> +static void __noreturn socfpga_restart_soc(struct device_d *dev)
>  {
>  	/* request a warm reset */
>  	writel((1 << RSTMGR_CTRL_SWWARMRSTREQ_LSB),
> @@ -47,5 +49,11 @@ void reset_cpu(ulong addr)
>  	 * infinite loop here as watchdog will trigger and reset
>  	 * the processor
>  	 */
> -	while (1);
> +	hang();
>  }
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(socfpga_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-tegra/tegra20-pmc.c b/arch/arm/mach-tegra/tegra20-pmc.c
> index 6493eea..58dca08 100644
> --- a/arch/arm/mach-tegra/tegra20-pmc.c
> +++ b/arch/arm/mach-tegra/tegra20-pmc.c
> @@ -36,13 +36,12 @@ static void __iomem *pmc_base;
>  static int tegra_num_powerdomains;
>  
>  /* main SoC reset trigger */
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn tegra20_restart_soc(struct device_d *dev)
>  {
>  	writel(PMC_CNTRL_MAIN_RST, pmc_base + PMC_CNTRL);
>  
> -	unreachable();
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
>  
>  static int tegra_powergate_set(int id, bool new_state)
>  {
> @@ -244,6 +243,7 @@ static struct driver_d tegra20_pmc_driver = {
>  
>  static int tegra20_pmc_init(void)
>  {
> +	restart_register_handler(tegra20_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  	return platform_driver_register(&tegra20_pmc_driver);
>  }
>  coredevice_initcall(tegra20_pmc_init);
> diff --git a/arch/arm/mach-uemd/reset.c b/arch/arm/mach-uemd/reset.c
> deleted file mode 100644
> index 00ae0be..0000000
> --- a/arch/arm/mach-uemd/reset.c
> +++ /dev/null
> @@ -1,24 +0,0 @@
> -/*
> - * Copyright (C) 2014 Antony Pavlov <antonynpavlov@gmail.com>
> - *
> - * This file is part of barebox.
> - * See file CREDITS for list of people who contributed to this project.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2
> - * as published by the Free Software Foundation.
> - *
> - * 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 <common.h>
> -
> -void __noreturn reset_cpu(ulong addr)
> -{
> -	hang();
> -}
> -EXPORT_SYMBOL(reset_cpu);
> diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
> index c671aa6..e2ceec6 100644
> --- a/arch/arm/mach-versatile/core.c
> +++ b/arch/arm/mach-versatile/core.c
> @@ -26,6 +26,7 @@
>  #include <init.h>
>  #include <clock.h>
>  #include <debug_ll.h>
> +#include <restart.h>
>  #include <linux/sizes.h>
>  
>  #include <linux/clkdev.h>
> @@ -184,7 +185,7 @@ void versatile_register_uart(unsigned id)
>  	amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0);
>  }
>  
> -void __noreturn reset_cpu (unsigned long ignored)
> +static void versatile_reset_soc(struct device_d *dev)
>  {
>  	u32 val;
>  
> @@ -195,9 +196,8 @@ void __noreturn reset_cpu (unsigned long ignored)
>  	__raw_writel(val, VERSATILE_SYS_RESETCTL);
>  	__raw_writel(0, VERSATILE_SYS_LOCK);
>  
> -	while(1);
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
>  
>  static int versatile_init(void)
>  {
> @@ -205,6 +205,7 @@ static int versatile_init(void)
>  	amba_apb_device_add(NULL, "pl061_gpio", 1, 0x101e5000, 4096, NULL, 0);
>  	amba_apb_device_add(NULL, "pl061_gpio", 2, 0x101e6000, 4096, NULL, 0);
>  	amba_apb_device_add(NULL, "pl061_gpio", 3, 0x101e7000, 4096, NULL, 0);
> +	restart_register_handler(versatile_reset_soc, NULL, FEATURE_SCOPE_SOC);
>  	return 0;
>  }
>  coredevice_initcall(versatile_init);
> diff --git a/arch/arm/mach-vexpress/reset.c b/arch/arm/mach-vexpress/reset.c
> index ad6e06f..1cbc2b3 100644
> --- a/arch/arm/mach-vexpress/reset.c
> +++ b/arch/arm/mach-vexpress/reset.c
> @@ -6,17 +6,24 @@
>  
>  #include <common.h>
>  #include <io.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <linux/amba/sp805.h>
>  
>  #include <mach/devices.h>
>  
>  void __iomem *v2m_wdt_base;
>  
> -void reset_cpu(ulong addr)
> +static void vexpress_reset_soc(struct device_d *dev)
>  {
>  	writel(LOAD_MIN, v2m_wdt_base + WDTLOAD);
>  	writeb(RESET_ENABLE, v2m_wdt_base + WDTCONTROL);
>  
> -	while (1)
> -		;
> +	hang();
>  }
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(vexpress_reset_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm/mach-zynq/zynq.c b/arch/arm/mach-zynq/zynq.c
> index bd29e13..b541da1 100644
> --- a/arch/arm/mach-zynq/zynq.c
> +++ b/arch/arm/mach-zynq/zynq.c
> @@ -17,6 +17,7 @@
>  #include <asm-generic/io.h>
>  #include <common.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <mach/zynq7000-regs.h>
>  
>  static int zynq_init(void)
> @@ -44,13 +45,18 @@ static int zynq_init(void)
>  }
>  postcore_initcall(zynq_init);
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn zynq_restart_soc(struct device_d *dev)
>  {
>  	/* write unlock key to slcr */
>  	writel(0xDF0D, ZYNQ_SLCR_UNLOCK);
>  	/* reset */
>  	writel(0x1, ZYNQ_PSS_RST_CTRL);
>  
> -	while (1)
> -		;
> +	hang();
>  }
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(zynq_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/blackfin/lib/cpu.c b/arch/blackfin/lib/cpu.c
> index 9d4c6e3..6c72e03 100644
> --- a/arch/blackfin/lib/cpu.c
> +++ b/arch/blackfin/lib/cpu.c
> @@ -27,8 +27,9 @@
>  #include <asm/entry.h>
>  #include <asm/cpu.h>
>  #include <init.h>
> +#include <restart.h>
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn blackfin_restart_cpu(struct device_d *dev)
>  {
>  	icache_disable();
>  
> @@ -41,9 +42,15 @@ void __noreturn reset_cpu(unsigned long addr)
>  	);
>  
>  	/* Not reached */
> -	while (1);
> +	hang();
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(blackfin_restart_cpu, NULL, FEATURE_SCOPE_CPU);
> +}
> +coredevice_initcall(restart_register_feature);
> +
>  void icache_disable(void)
>  {
>  #ifdef __ADSPBF537__
> diff --git a/arch/efi/efi/efi.c b/arch/efi/efi/efi.c
> index d351775..9d8110b 100644
> --- a/arch/efi/efi/efi.c
> +++ b/arch/efi/efi/efi.c
> @@ -24,6 +24,7 @@
>  #include <command.h>
>  #include <magicvar.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <driver.h>
>  #include <ns16550.h>
>  #include <io.h>
> @@ -246,13 +247,19 @@ static int efi_console_init(void)
>  }
>  console_initcall(efi_console_init);
>  
> -void reset_cpu(unsigned long addr)
> +static void __noreturn efi_restart_system(struct device_d *dev)
>  {
>  	RT->reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
>  
> -	while(1);
> +	hang();
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(efi_restart_cpu, NULL, FEATURE_SCOPE_MACHINE);
> +}
> +coredevice_initcall(restart_register_feature);
> +
>  extern char image_base[];
>  extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
>  		  __barebox_initcalls_end[];
> diff --git a/arch/mips/mach-ar231x/ar231x_reset.c b/arch/mips/mach-ar231x/ar231x_reset.c
> index 0788add..3724bbe 100644
> --- a/arch/mips/mach-ar231x/ar231x_reset.c
> +++ b/arch/mips/mach-ar231x/ar231x_reset.c
> @@ -10,6 +10,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <io.h>
> +#include <restart.h>
>  #include <linux/err.h>
>  
>  #include <mach/ar2312_regs.h>
> @@ -17,16 +18,16 @@
>  
>  static void __iomem *reset_base;
>  
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn ar2312x_restart_soc(struct device_d *dev)
>  {
>  	printf("reseting cpu\n");
>  	__raw_writel(0x10000,
>  		(char *)KSEG1ADDR(AR2312_WD_TIMER));
>  	__raw_writel(AR2312_WD_CTRL_RESET,
>  		(char *)KSEG1ADDR(AR2312_WD_CTRL));
> -	unreachable();
> +
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
>  
>  static u32 ar231x_reset_readl(void)
>  {
> @@ -69,6 +70,7 @@ static struct driver_d ar231x_reset_driver = {
>  
>  static int ar231x_reset_init(void)
>  {
> +	restart_register_handler(ar2312x_restart_soc, NULL, FEATURE_SCOPE_SOC);
>  	return platform_driver_register(&ar231x_reset_driver);
>  }
>  coredevice_initcall(ar231x_reset_init);
> diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c
> index a0e9b34..757027f 100644
> --- a/arch/mips/mach-ath79/reset.c
> +++ b/arch/mips/mach-ath79/reset.c
> @@ -16,9 +16,11 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/ath79.h>
>  
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn ath79_restart_soc(struct device_d *dev)
>  {
>  	ath79_reset_wr(AR933X_RESET_REG_RESET_MODULE, AR71XX_RESET_FULL_CHIP);
>  	/*
> @@ -26,7 +28,12 @@ void __noreturn reset_cpu(ulong addr)
>  	 * pulling the reset pin. The system will reboot with PLL disabled.
>  	 * Always zero when read.
>  	 */
> -	unreachable();
> +	hang();
>  	/*NOTREACHED*/
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(ath79_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/mips/mach-bcm47xx/reset.c b/arch/mips/mach-bcm47xx/reset.c
> index 00aee19..332047d 100644
> --- a/arch/mips/mach-bcm47xx/reset.c
> +++ b/arch/mips/mach-bcm47xx/reset.c
> @@ -17,12 +17,20 @@
>  
>  #include <common.h>
>  #include <io.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/hardware.h>
>  
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn bcm47xx_restart_soc(struct device_d *dev)
>  {
>  	__raw_writel(GORESET, (char *)SOFTRES_REG);
> -	while (1);
> +
> +	hang();
>  	/*NOTREACHED*/
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(bcm47xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/mips/mach-loongson/loongson1_reset.c b/arch/mips/mach-loongson/loongson1_reset.c
> index 8975392..fe02da6 100644
> --- a/arch/mips/mach-loongson/loongson1_reset.c
> +++ b/arch/mips/mach-loongson/loongson1_reset.c
> @@ -14,14 +14,21 @@
>  
>  #include <common.h>
>  #include <io.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/loongson1.h>
>  
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn longhorn_restart_soc(struct device_d *dev)
>  {
>  	__raw_writel(0x1, LS1X_WDT_EN);
>  	__raw_writel(0x1, LS1X_WDT_SET);
>  	__raw_writel(0x1, LS1X_WDT_TIMER);
>  
> -	unreachable();
> +	hang();
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(longhorn_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/mips/mach-malta/reset.c b/arch/mips/mach-malta/reset.c
> index f1dc68a..066535c 100644
> --- a/arch/mips/mach-malta/reset.c
> +++ b/arch/mips/mach-malta/reset.c
> @@ -22,12 +22,20 @@
>  
>  #include <common.h>
>  #include <io.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <mach/hardware.h>
>  
> -void __noreturn reset_cpu(ulong addr)
> +static void __noreturn malta_restart_soc(struct device_d *dev)
>  {
>  	__raw_writel(GORESET, (char *)SOFTRES_REG);
> -	while (1);
> +
> +	hang();
>  	/*NOTREACHED*/
>  }
> -EXPORT_SYMBOL(reset_cpu);
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(malta_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/nios2/cpu/cpu.c b/arch/nios2/cpu/cpu.c
> index fdbe9f9..3ede3b8 100644
> --- a/arch/nios2/cpu/cpu.c
> +++ b/arch/nios2/cpu/cpu.c
> @@ -18,14 +18,22 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <asm/system.h>
>  
> -void __noreturn reset_cpu(ulong ignored)
> +static void __noreturn nios2_restart_soc(struct device_d *dev)
>  {
>  	/* indirect call to go beyond 256MB limitation of toolchain */
>  	nios2_callr(RESET_ADDR);
>  
>  	/* Not reached */
> -	while (1);
> +	hang();
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(nios2_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> +
> diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c
> index d73a418..6cedb26 100644
> --- a/arch/openrisc/cpu/cpu.c
> +++ b/arch/openrisc/cpu/cpu.c
> @@ -19,6 +19,7 @@
>  
>  #include <common.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <asm/system.h>
>  #include <asm/openrisc_exc.h>
>  
> @@ -29,11 +30,17 @@ int cleanup_before_linux(void)
>  
>  extern void __reset(void);
>  
> -void __noreturn reset_cpu(ulong ignored)
> +static void __noreturn openrisc_restart_cpu(struct device_d *dev)
>  {
>  	__reset();
>  	/* not reached, __reset does not return */
>  
>  	/* Not reached */
> -	while (1);
> +	hang();
>  }
> +
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(openrisc_restart_cpu, NULL, FEATURE_SCOPE_CPU);
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/ppc/mach-mpc5xxx/cpu.c b/arch/ppc/mach-mpc5xxx/cpu.c
> index c860e70..c11a6cd 100644
> --- a/arch/ppc/mach-mpc5xxx/cpu.c
> +++ b/arch/ppc/mach-mpc5xxx/cpu.c
> @@ -31,6 +31,7 @@
>  #include <types.h>
>  #include <errno.h>
>  #include <of.h>
> +#include <restart.h>
>  #include <mach/clocks.h>
>  
>  int checkcpu (void)
> @@ -59,7 +60,7 @@ int checkcpu (void)
>  
>  /* ------------------------------------------------------------------------- */
>  
> -void __noreturn reset_cpu (unsigned long addr)
> +static void __noreturn mpc5xxx_restart_soc(struct device_d *dev)
>  {
>  	ulong msr;
>  	/* Interrupts and MMU off */
> @@ -71,9 +72,15 @@ void __noreturn reset_cpu (unsigned long addr)
>  	/* Charge the watchdog timer */
>  	*(vu_long *)(MPC5XXX_GPT0_COUNTER) = 0x0001000f;
>  	*(vu_long *)(MPC5XXX_GPT0_ENABLE) = 0x9004; /* wden|ce|timer_ms */
> -	while(1);
> +	hang();
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(mpc5xxx_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> +
>  /* ------------------------------------------------------------------------- */
>  
>  #ifdef CONFIG_OFTREE
> diff --git a/arch/ppc/mach-mpc85xx/cpu.c b/arch/ppc/mach-mpc85xx/cpu.c
> index 7c183c1..a3fedae 100644
> --- a/arch/ppc/mach-mpc85xx/cpu.c
> +++ b/arch/ppc/mach-mpc85xx/cpu.c
> @@ -26,12 +26,13 @@
>  #include <common.h>
>  #include <memory.h>
>  #include <init.h>
> +#include <restart.h>
>  #include <asm/fsl_ddr_sdram.h>
>  #include <asm-generic/memory_layout.h>
>  #include <mach/mmu.h>
>  #include <mach/immap_85xx.h>
>  
> -void __noreturn reset_cpu(unsigned long addr)
> +static void __noreturn mpc85xx_restart_soc(struct device_d *dev)
>  {
>  	void __iomem *regs = (void __iomem *)MPC85xx_GUTS_ADDR;
>  
> @@ -39,10 +40,15 @@ void __noreturn reset_cpu(unsigned long addr)
>  	out_be32(regs + MPC85xx_GUTS_RSTCR_OFFSET, 0x2);  /* HRESET_REQ */
>  	udelay(100);
>  
> -	while (1)
> -		;
> +	hang();
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(mpc85xx_restart_soc, NULL, FEATURE_SCOPE_SOC);
> +}
> +coredevice_initcall(restart_register_feature);
> +
>  long int initdram(int board_type)
>  {
>  	phys_size_t dram_size = 0;
> diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
> index d627391..61a816e 100644
> --- a/arch/sandbox/os/common.c
> +++ b/arch/sandbox/os/common.c
> @@ -28,6 +28,8 @@
>  #include <termios.h>
>  #include <unistd.h>
>  #include <fcntl.h>
> +#include <init.h>
> +#include <restart.h>
>  #include <time.h>
>  #include <getopt.h>
>  #include <sys/types.h>
> @@ -115,12 +117,18 @@ uint64_t linux_get_time(void)
>  	return now;
>  }
>  
> -void __attribute__((noreturn)) reset_cpu(unsigned long addr)
> +static void __attribute__((noreturn)) sandbox_restart_cpu(struct device_d *dev)
>  {
>  	cookmode();
>  	exit(0);
>  }
>  
> +static int restart_register_feature(void)
> +{
> +	restart_register_handler(sandbox_restart_cpu, NULL, FEATURE_SCOPE_CPU);
> +}
> +coredevice_initcall(restart_register_feature);
> +
>  int linux_read(int fd, void *buf, size_t count)
>  {
>  	ssize_t ret;
> diff --git a/arch/x86/mach-i386/reset.c b/arch/x86/mach-i386/reset.c
> deleted file mode 100644
> index 65f7d35..0000000
> --- a/arch/x86/mach-i386/reset.c
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -/*
> - * Copyright (C) 2009 Juergen Beisert, Pengutronix
> - *
> - * 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.
> - *
> - *
> - */
> -
> -/**
> - * @file
> - * @brief Resetting an x86 CPU
> - */
> -
> -#include <common.h>
> -
> -void __noreturn reset_cpu(unsigned long addr)
> -{
> -	/** How to reset the machine? */
> -	while(1)
> -		;
> -}
> -EXPORT_SYMBOL(reset_cpu);
> diff --git a/commands/reset.c b/commands/reset.c
> index 4f42b91..8300480 100644
> --- a/commands/reset.c
> +++ b/commands/reset.c
> @@ -21,6 +21,7 @@
>  #include <command.h>
>  #include <complete.h>
>  #include <getopt.h>
> +#include <restart.h>
>  
>  static int cmd_reset(int argc, char *argv[])
>  {
> @@ -39,7 +40,7 @@ static int cmd_reset(int argc, char *argv[])
>  	if (shutdown_flag)
>  		shutdown_barebox();
>  
> -	reset_cpu(0);
> +	restart_machine();
>  
>  	/* Not reached */
>  	return 1;
> diff --git a/common/misc.c b/common/misc.c
> index 6da71c7..5532349 100644
> --- a/common/misc.c
> +++ b/common/misc.c
> @@ -24,6 +24,7 @@
>  #include <environment.h>
>  #include <led.h>
>  #include <of.h>
> +#include <restart.h>
>  
>  int errno;
>  EXPORT_SYMBOL(errno);
> @@ -206,7 +207,7 @@ void __noreturn panic(const char *fmt, ...)
>  		hang();
>  	} else {
>  		udelay(100000);	/* allow messages to go out */
> -		reset_cpu(0);
> +		restart_machine();
>  	}
>  }
>  EXPORT_SYMBOL(panic);
> diff --git a/common/restart.c b/common/restart.c
> index f73a9da..67797e4 100644
> --- a/common/restart.c
> +++ b/common/restart.c
> @@ -65,9 +65,64 @@ void reset_source_set(enum reset_src_type st, enum f_scope scope)
>  }
>  EXPORT_SYMBOL(reset_source_set);
>  
> +/* handle machine restart feature */
> +
> +static struct device_d *resetd;
> +static void (*resetf)(struct device_d*);
> +static int restart_scope;
> +
> +void __noreturn restart_machine(void)
> +{
> +	if (resetf != NULL)
> +		resetf(resetd);
> +	else
> +		pr_err("No restart handler available. Cannot restart system, hanging instead\n");

Can we save a few bytes here? "No restart handler registered" should be
enough, no?

> +	hang();
> +}
> +
> +static void restart_update_global_info(void)
> +{
> +	globalvar_add_simple("system.restart.unit",
> +				resetd == NULL ? "unknown" : resetd->name);
> +	globalvar_add_simple_enum("system.reset.scope", &restart_scope,
> +					scope_names, ARRAY_SIZE(scope_names));
> +}
> +
> +int restart_register_handler(void (*func)(struct device_d*), struct device_d *dev, enum f_scope scope)
> +{
> +	/* calling with a lower or equal scope will be ignored and is not a failure */
> +	if ((int)scope <= restart_scope)
> +		return 0;
> +
> +	resetf = func;
> +	resetd = dev;
> +	restart_scope = (int)scope;
> +	restart_update_global_info();

This call is unnecessary.

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(restart_register_handler);
> +
> +int restart_remove_handler(void (*func)(struct device_d*), struct device_d *dev)

void instead? I think no caller will be prepared for something else.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/5] Watchdog: add a scope value to the watchdog feature
  2015-06-23 12:58 ` [PATCH 3/5] Watchdog: add a scope value to the watchdog feature Juergen Borleis
@ 2015-06-24  6:51   ` Sascha Hauer
  0 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2015-06-24  6:51 UTC (permalink / raw)
  To: Juergen Borleis; +Cc: barebox

On Tue, Jun 23, 2015 at 02:58:02PM +0200, Juergen Borleis wrote:
> Sometimes the SoC internal watchdogs are inappropriate to restart the
> machine in a reliable manner. This change should help to handle more than
> one watchdog unit by adding a scope parameter. The framework always
> prefers the watchdog with the widest scope. For example a watchdog
> which is able to restart the whole machine (SoC + external devices) gets
> precedence over a watchdog which can restart the SoC only.
> 
> Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
> ---
>  Documentation/user/user-manual.rst |  1 +
>  Documentation/user/watchdog.rst    | 74 ++++++++++++++++++++++++++++++++++++++
>  common/restart.c                   |  6 ++++
>  drivers/watchdog/im28wd.c          |  1 +
>  drivers/watchdog/imxwd.c           |  1 +
>  drivers/watchdog/wd_core.c         | 24 +++++++++++--
>  include/watchdog.h                 |  3 ++
>  7 files changed, 108 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/user/watchdog.rst
> 
> diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
> index 0d6daee..8a32469 100644
> --- a/Documentation/user/user-manual.rst
> +++ b/Documentation/user/user-manual.rst
> @@ -30,6 +30,7 @@ Contents:
>     system-setup
>     reset-reason
>     system-reset
> +   watchdog
>  
>  * :ref:`search`
>  * :ref:`genindex`
> diff --git a/Documentation/user/watchdog.rst b/Documentation/user/watchdog.rst
> new file mode 100644
> index 0000000..d8e6e76
> --- /dev/null
> +++ b/Documentation/user/watchdog.rst
> @@ -0,0 +1,74 @@
> +.. _watchdog_usage:
> +
> +Using a watchdog
> +----------------
> +
> +Watchdogs are commonly used to prevent bad software from hanging the whole
> +system for ever. Sometimes a simple approach can help to make a system work
> +if hanging failures are happen very seldom: just restart the system and do
> +everything again in the same way as it was done when the system starts the
> +last time.
> +
> +But using a watchdog should always be the 'last resort' to keep a machine
> +working. The focus should still be on finding and fixing the bug ;)
> +
> +A more complex way to use a watchdog in a real-word example is when the state
> +frameworks comes into play. Then the watchdog's task isn't only to keep the
> +machine working. It also monitors the whole health of the machine including
> +hardware and software. Especially something like a firmware update can go
> +wrong: a wrong firmware was programmed (wrong release or for a different machine),
> +programming was incomplete due to a user intervention or power fail and so on.
> +
> +In this case the watchdog does not just restart the system if the software hangs,
> +it also provides 'additional' information about the firmware by this restart.
> +The barebox's state framework is now able to run some kind of state machine to handle
> +firmware updates in a correct manner: trying the new firmware once and if it fails falling
> +back to the previous firmware (if available) for example.
> +
> +Refer the :ref:`reset_reason` how to detect the reason why the bootloader runs.
> +This information can be used by the barebox's state framework.
> +
> +.. _watchdog_restart_pitfalls:
> +
> +Watchdog Pitfalls
> +~~~~~~~~~~~~~~~~~
> +
> +If a watchdog triggers a machine restart it suffers from the same issues like
> +a regular user triggered system machine restart. Refer :ref:`system_reset_pitfalls`
> +for further details.
> +So keep this in mind when you select an available watchdog on your machine for
> +this task. And if you are a hardware designer keep this in mind even more, and
> +provide a reliable restart source for the software developers and to keep their
> +headache low.
> +
> +Watchdogs from the developers point of view
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Watchdogs gets registered in barebox with a scope. When you register your own
> +watchdog driver, check its hardware scope carefully and use one of the
> +definitions from the file ``include/restart.h``.
> +
> +The list of defined scopes (defined in file ``include/restart.h``):
> +
> +* ``FEATURE_SCOPE_UNKNOWN``: completely useless watchdog, maybe a last resort..
> +* ``FEATURE_SCOPE_CPU``: this watchdog is able to restart the core CPU only.
> +  Regarding to the issues in :ref:`system_reset_pitfalls` this kind of watchdog
> +  seems more or less useless.
> +* ``FEATURE_SCOPE_SOC``: this watchdog is able to restart the whole SoC. Regarding
> +  to the issues in :ref:`system_reset_pitfalls` this scope is more reliable, but
> +  depends on the machine and its hardware design if is able to bring the machine
> +  back into life under every circumstance.
> +* ``FEATURE_SCOPE_MACHINE``: it is able to restart the whole machine and does
> +  the same like a real ``POR`` does. Best scope and always reliable.
> +
> +The selected scope is very important because barebox will always use
> +the watchdog with the best available scope.
> +
> +But that is true only for watchdogs used in barebox and as long barebox is
> +running.
> +
> +If an operating system runs later on, it is the task of this OS to use a watchdog
> +with a correct scope. Otherwise it suffers from the :ref:`system_reset_pitfalls`
> +as well. This is even more important if the state framework is used. That means
> +barebox and the operating system must use the same watchdog in order to check
> +and change the states correctly.
> diff --git a/common/restart.c b/common/restart.c
> index 67797e4..c0c4861 100644
> --- a/common/restart.c
> +++ b/common/restart.c
> @@ -119,6 +119,12 @@ int restart_remove_handler(void (*func)(struct device_d*), struct device_d *dev)
>  }
>  EXPORT_SYMBOL(restart_remove_handler);
>  
> +void watchdog_update_global_info(int *scope)
> +{
> +	globalvar_add_simple_enum("system.wd.scope", scope,
> +				scope_names, ARRAY_SIZE(scope_names));
> +}
> +
>  static int reset_feature_init(void)
>  {
>  	reset_source_update_global_info();
> diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c
> index c824a25..918d37a 100644
> --- a/drivers/watchdog/im28wd.c
> +++ b/drivers/watchdog/im28wd.c
> @@ -197,6 +197,7 @@ static int imx28_wd_probe(struct device_d *dev)
>  	if (IS_ERR(priv->regs))
>  		return PTR_ERR(priv->regs);
>  	priv->wd.set_timeout = imx28_watchdog_set_timeout;
> +	priv->wd.scope = FEATURE_SCOPE_SOC;
>  
>  	if (!(readl(priv->regs + MXS_RTC_STAT) & MXS_RTC_STAT_WD_PRESENT)) {
>  		rc = -ENODEV;
> diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
> index 3cbae09..60772b1 100644
> --- a/drivers/watchdog/imxwd.c
> +++ b/drivers/watchdog/imxwd.c
> @@ -185,6 +185,7 @@ static int imx_wd_probe(struct device_d *dev)
>  	}
>  	priv->ops = ops;
>  	priv->wd.set_timeout = imx_watchdog_set_timeout;
> +	priv->wd.scope = FEATURE_SCOPE_SOC;
>  	priv->dev = dev;
>  
>  	if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) {
> diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
> index 3d0cfc6..6386cf3 100644
> --- a/drivers/watchdog/wd_core.c
> +++ b/drivers/watchdog/wd_core.c
> @@ -13,22 +13,32 @@
>   */
>  
>  #include <common.h>
> +#include <init.h>
>  #include <command.h>
>  #include <errno.h>
>  #include <linux/ctype.h>
>  #include <watchdog.h>
> +#include <globalvar.h>
> +#include <restart.h>
>  
>  /*
>   * Note: this simple framework supports one watchdog only.
>   */
>  static struct watchdog *watchdog;
> +static int watchdog_scope;
> +
> +void watchdog_update_global_info(int*);
>  
>  int watchdog_register(struct watchdog *wd)
>  {
> -	if (watchdog != NULL)
> -		return -EBUSY;
> +	/* ignore a lower or same priority, it isn't a failure */
> +	if (wd->scope <= watchdog_scope)
> +		return 0;
>  
>  	watchdog = wd;
> +	watchdog_scope = (int)wd->scope;

I don't think we have to make this explicit cast from enum to int.

> +	watchdog_update_global_info(&watchdog_scope);

Unnecessary.

> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(watchdog_register);
> @@ -39,6 +49,9 @@ int watchdog_deregister(struct watchdog *wd)
>  		return -ENODEV;
>  
>  	watchdog = NULL;
> +	watchdog_scope = (int)FEATURE_SCOPE_UNKNOWN;
> +	watchdog_update_global_info(&watchdog_scope);

Unnecessary.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/5] Reset reason: add a scope value to the reset reason feature
  2015-06-24  6:32   ` Sascha Hauer
@ 2015-06-24  7:35     ` Juergen Borleis
  0 siblings, 0 replies; 11+ messages in thread
From: Juergen Borleis @ 2015-06-24  7:35 UTC (permalink / raw)
  To: barebox

Hi Sascha,

On Wednesday 24 June 2015 08:32:47 Sascha Hauer wrote:
> [...]
> > +void reset_source_set(enum reset_src_type st, enum f_scope scope)
> > +{
> > +	if ((int)scope <= reset_source_scope)
> > +		return; /* just ignore this setting */
> > +
> > +	reset_source = (int)st;
> > +	reset_source_scope = (int)scope;
> > +	reset_source_update_global_info();
>
> This call is unnecessary. You can call globalvar_add_simple_enum()
> directly from the initcall.

It took me longer to understand your comment here... Yes, sure. 
globalvar_add_simple_enum() do all the necessary things in background.

Thanks, will change it.

jbe

-- 
Pengutronix e.K.                              | Juergen Borleis             |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 5/5] MFD/DA9053: da9053: add basic da9053 driver
  2015-06-25  7:34 [PATCHv3] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
@ 2015-06-25  7:34 ` Juergen Borleis
  0 siblings, 0 replies; 11+ messages in thread
From: Juergen Borleis @ 2015-06-25  7:34 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
---
 drivers/mfd/Kconfig  |   8 ++
 drivers/mfd/Makefile |   1 +
 drivers/mfd/da9053.c | 337 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 346 insertions(+)
 create mode 100644 drivers/mfd/da9053.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3af904d..6ec66ac 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -4,6 +4,14 @@ config MFD_ACT8846
 	depends on I2C
 	bool "ACT8846 driver"
 
+config MFD_DA9053
+	depends on I2C
+	bool "DA9053 PMIC driver"
+	help
+	  This power management controller provides configureable power supplies,
+	  a machine restart feature and a watchdog which are effective machine
+	  wide.
+
 config MFD_LP3972
 	depends on I2C
 	bool "LP3972 driver"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 49b9e35..2899dde 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_MFD_ACT8846)	+= act8846.o
+obj-$(CONFIG_MFD_DA9053)	+= da9053.o
 obj-$(CONFIG_MFD_LP3972)	+= lp3972.o
 obj-$(CONFIG_MFD_MC13XXX)	+= mc13xxx.o
 obj-$(CONFIG_MFD_MC34704)	+= mc34704.o
diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c
new file mode 100644
index 0000000..6e86195
--- /dev/null
+++ b/drivers/mfd/da9053.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2013 Jan Luebbe <jlu@pengutronix.de>
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <watchdog.h>
+
+#include <i2c/i2c.h>
+#include <restart.h>
+#include <restart.h>
+
+#define DRIVERNAME		"da9053"
+
+/* STATUS REGISTERS */
+#define DA9053_STATUS_A_REG		1
+#define DA9053_STATUS_B_REG		2
+#define DA9053_STATUS_C_REG		3
+#define DA9053_STATUS_D_REG		4
+
+/* PARK REGISTER */
+#define DA9053_PARK_REGISTER		DA9053_STATUS_D_REG
+
+/* EVENT REGISTERS */
+#define DA9053_EVENT_A_REG		5
+#define DA9053_EVENT_B_REG		6
+#define DA9053_EVENT_C_REG		7
+#define DA9053_EVENT_D_REG		8
+#define DA9053_FAULTLOG_REG		9
+
+/* IRQ REGISTERS */
+#define DA9053_IRQ_MASK_A_REG		10
+#define DA9053_IRQ_MASK_B_REG		11
+#define DA9053_IRQ_MASK_C_REG		12
+#define DA9053_IRQ_MASK_D_REG		13
+
+/* CONTROL REGISTERS */
+#define DA9053_CONTROL_A_REG		14
+#define DA9053_CONTROL_B_REG		15
+#define DA9053_CONTROL_C_REG		16
+#define DA9053_CONTROL_D_REG		17
+
+#define DA9053_PDDIS_REG		18
+#define DA9053_INTERFACE_REG		19
+#define DA9053_RESET_REG		20
+
+/* FAULT LOG REGISTER BITS */
+#define DA9053_FAULTLOG_WAITSET		0X80
+#define DA9053_FAULTLOG_NSDSET		0X40
+#define DA9053_FAULTLOG_KEYSHUT		0X20
+#define DA9053_FAULTLOG_TEMPOVER	0X08
+#define DA9053_FAULTLOG_VDDSTART	0X04
+#define DA9053_FAULTLOG_VDDFAULT	0X02
+#define DA9053_FAULTLOG_TWDERROR	0X01
+
+/* CONTROL REGISTER B BITS */
+#define DA9053_CONTROLB_SHUTDOWN	0X80
+#define DA9053_CONTROLB_DEEPSLEEP	0X40
+#define DA9053_CONTROLB_WRITEMODE	0X20
+#define DA9053_CONTROLB_BBATEN		0X10
+#define DA9053_CONTROLB_OTPREADEN	0X08
+#define DA9053_CONTROLB_AUTOBOOT	0X04
+#define DA9053_CONTROLB_ACTDIODE	0X02
+#define DA9053_CONTROLB_BUCKMERGE	0X01
+
+/* CONTROL REGISTER D BITS */
+#define DA9053_CONTROLD_WATCHDOG	0X80
+#define DA9053_CONTROLD_ACCDETEN	0X40
+#define DA9053_CONTROLD_GPI1415SD	0X20
+#define DA9053_CONTROLD_NONKEYSD	0X10
+#define DA9053_CONTROLD_KEEPACTEN	0X08
+#define DA9053_CONTROLD_TWDSCALE	0X07
+
+struct da9053_priv {
+	struct cdev		cdev;
+	struct watchdog		wd;
+	struct i2c_client	*client;
+};
+
+#define cdev_to_da9053_priv(x)	container_of(x, struct da9053_priv, cdev)
+#define wd_to_da9053_priv(x)	container_of(x, struct da9053_priv, wd)
+
+static int da9053_reg_read(struct da9053_priv *da9053, u32 reg, u8 *val)
+{
+	int ret;
+
+	ret = i2c_read_reg(da9053->client, reg, val, 1);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static int da9053_reg_write(struct da9053_priv *da9053, u32 reg, u8 val)
+{
+	int ret;
+
+	ret = i2c_write_reg(da9053->client, reg, &val, 1);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static int da9053_park(struct da9053_priv *da9053)
+{
+	int ret;
+	u8 val;
+
+	ret = i2c_read_reg(da9053->client, DA9053_PARK_REGISTER, &val, 1);
+
+	return ret == 1 ? 0 : ret;
+}
+
+static ssize_t da9053_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+	struct da9053_priv *da9053 = cdev_to_da9053_priv(cdev);
+	u8 *buf = _buf;
+	size_t i = count;
+	int err;
+
+	while (i) {
+		err = da9053_reg_read(da9053, offset, buf);
+		if (err) {
+			da9053_park(da9053);
+			return (ssize_t)err;
+		}
+		buf++;
+		i--;
+		offset++;
+	}
+
+	if (da9053_park(da9053) < 0)
+		return -EIO;
+
+	return count;
+}
+
+static int da9053_enable_multiwrite(struct da9053_priv *da9053)
+{
+	int ret;
+	u8 val;
+
+	ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val & DA9053_CONTROLB_WRITEMODE) {
+		val &= ~DA9053_CONTROLB_WRITEMODE;
+		ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = da9053_park(da9053);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct file_operations da9053_fops = {
+	.lseek	= dev_lseek_default,
+	.read	= da9053_read,
+};
+
+static int da9053_set_timeout(struct watchdog *wd, unsigned timeout)
+{
+	struct da9053_priv *da9053 = wd_to_da9053_priv(wd);
+	struct device_d *dev = da9053->cdev.dev;
+	unsigned scale = 0;
+	int ret;
+	u8 val;
+
+	if (timeout > 131)
+		return -EINVAL;
+
+	if (timeout) {
+		timeout *= 1000; /* convert to ms */
+		scale = 0;
+		while (timeout > (2048 << scale) && scale <= 6)
+			scale++;
+		dev_dbg(dev, "calculated TWDSCALE=%u (req=%ims calc=%ims)\n",
+		        scale, timeout, 2048 << scale);
+		scale++; /* scale 0 disables the WD */
+	}
+
+	ret = da9053_reg_read(da9053, DA9053_CONTROL_D_REG, &val);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "read watchdog (val=0x%02x)\n", val);
+
+	if (scale && scale == (val & DA9053_CONTROLD_TWDSCALE)) {
+		/* trigger WD */
+		val |= DA9053_CONTROLD_WATCHDOG;
+		ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+		if (ret < 0)
+			return ret;
+		dev_dbg(dev, "triggered watchdog (val=0x%02x)\n", val);
+	} else {
+		/* disable WD first */
+		val &= ~DA9053_CONTROLD_TWDSCALE;
+		ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+		if (ret < 0)
+			return ret;
+
+		dev_dbg(dev, "disabled watchdog (val=0x%02x)\n", val);
+		if (scale) {
+			/* park before waiting */
+			ret = da9053_park(da9053);
+			if (ret < 0)
+				return ret;
+
+			/* wait required time */
+			udelay(150);
+
+			/* enable WD with new timeout */
+			val |= scale;
+			ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+			if (ret < 0)
+				return ret;
+			dev_dbg(dev, "enabled watchdog (val=0x%02x)\n", val);
+		}
+	}
+
+	ret = da9053_park(da9053);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void da9053_detect_reset_source(struct da9053_priv *da9053)
+{
+	int ret;
+	u8 val;
+
+	ret = da9053_reg_read(da9053, DA9053_FAULTLOG_REG, &val);
+	if (ret < 0)
+		return;
+
+	ret = da9053_park(da9053);
+	if (ret < 0)
+		return;
+
+	if (val & DA9053_FAULTLOG_TWDERROR) {
+		reset_source_set(RESET_WDG, FEATURE_SCOPE_MACHINE);
+		return;
+	}
+
+	if (val & DA9053_FAULTLOG_VDDFAULT) {
+		reset_source_set(RESET_POR, FEATURE_SCOPE_MACHINE);
+		return;
+	}
+
+	if (val & DA9053_FAULTLOG_NSDSET) {
+		reset_source_set(RESET_RST, FEATURE_SCOPE_MACHINE);
+		return;
+	}
+
+	/* else keep the default 'unknown' state */
+}
+
+static void __noreturn da9053_force_system_reset(struct device_d *dev)
+{
+	struct da9053_priv *da9053 = dev->priv;
+	u8 val;
+	int ret;
+
+	ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val);
+	if (ret < 0)
+		hang();
+
+	val |= DA9053_CONTROLB_SHUTDOWN;
+	ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val);
+	if (ret < 0)
+		hang();
+
+	da9053_park(da9053);
+
+	hang();
+}
+
+static int da9053_probe(struct device_d *dev)
+{
+	struct da9053_priv *da9053;
+	int ret;
+
+	da9053 = xzalloc(sizeof(struct da9053_priv));
+	dev->priv = da9053;
+	da9053->cdev.name = DRIVERNAME;
+	da9053->client = to_i2c_client(dev);
+	da9053->cdev.size = 128;
+	da9053->cdev.dev = dev;
+	da9053->cdev.ops = &da9053_fops;
+	da9053->wd.set_timeout = da9053_set_timeout;
+	da9053->wd.scope = FEATURE_SCOPE_MACHINE;
+
+	ret = da9053_enable_multiwrite(da9053);
+	if (ret < 0)
+		return ret;
+
+	ret = watchdog_register(&da9053->wd);
+	if (ret)
+		return ret;
+
+	da9053_detect_reset_source(da9053);
+
+	restart_register_handler(da9053_force_system_reset, dev, FEATURE_SCOPE_MACHINE);
+
+	return 0;
+}
+
+static struct driver_d da9053_driver = {
+	.name  = DRIVERNAME,
+	.probe = da9053_probe,
+};
+
+static int da9053_init(void)
+{
+	i2c_driver_register(&da9053_driver);
+	return 0;
+}
+
+device_initcall(da9053_init);
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-06-25  7:35 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-23 12:57 [PATCHv2] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
2015-06-23 12:58 ` [PATCH 1/5] Reset reason: add a scope value to the reset reason feature Juergen Borleis
2015-06-24  6:32   ` Sascha Hauer
2015-06-24  7:35     ` Juergen Borleis
2015-06-23 12:58 ` [PATCH 2/5] System restart: add a scope value to the system restart feature Juergen Borleis
2015-06-24  6:42   ` Sascha Hauer
2015-06-23 12:58 ` [PATCH 3/5] Watchdog: add a scope value to the watchdog feature Juergen Borleis
2015-06-24  6:51   ` Sascha Hauer
2015-06-23 12:58 ` [PATCH 4/5] Watchdog/i.MX: make the watchdog driver a regular driver Juergen Borleis
2015-06-23 12:58 ` [PATCH 5/5] MFD/DA9053: da9053: add basic da9053 driver Juergen Borleis
2015-06-25  7:34 [PATCHv3] Change barebox regarding "machine-restart", "reset cause detection" und "watchdog usage" Juergen Borleis
2015-06-25  7:34 ` [PATCH 5/5] MFD/DA9053: da9053: add basic da9053 driver Juergen Borleis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox