diff options
Diffstat (limited to 'configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch')
-rw-r--r-- | configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch | 1467 |
1 files changed, 0 insertions, 1467 deletions
diff --git a/configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch b/configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch deleted file mode 100644 index d665772..0000000 --- a/configs/platform-v7a/patches/barebox-2016.05.0/0001-bootstate-add-framework-for-redundant-boot-scenarios.patch +++ /dev/null @@ -1,1467 +0,0 @@ -From: Marc Kleine-Budde <mkl@pengutronix.de> -Date: Fri, 20 Feb 2015 09:19:14 +0100 -Subject: [PATCH] bootstate: add framework for redundant boot scenarios - -There are several use cases where a redundant Linux system is needed. The -barebox,bootstate framework provides the building blocks to model different -use cases without the need to start from the scratch over and over again. - -Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> ---- - .../bindings/barebox/barebox,bootstate.rst | 236 +++++++ - arch/sandbox/dts/sandbox.dts | 83 +++ - commands/Kconfig | 5 + - commands/Makefile | 1 + - commands/bootchooser.c | 101 +++ - common/Kconfig | 8 + - common/Makefile | 1 + - common/bootstate.c | 781 +++++++++++++++++++++ - drivers/misc/Kconfig | 5 + - drivers/misc/Makefile | 1 + - drivers/misc/bootstate.c | 79 +++ - include/bootstate.h | 39 + - 12 files changed, 1340 insertions(+) - create mode 100644 Documentation/devicetree/bindings/barebox/barebox,bootstate.rst - create mode 100644 commands/bootchooser.c - create mode 100644 common/bootstate.c - create mode 100644 drivers/misc/bootstate.c - create mode 100644 include/bootstate.h - -diff --git a/Documentation/devicetree/bindings/barebox/barebox,bootstate.rst b/Documentation/devicetree/bindings/barebox/barebox,bootstate.rst -new file mode 100644 -index 000000000000..0f7131536798 ---- /dev/null -+++ b/Documentation/devicetree/bindings/barebox/barebox,bootstate.rst -@@ -0,0 +1,236 @@ -+barebox bootstate -+================= -+ -+Overview -+-------- -+ -+There are several use cases where a redundant Linux system is needed. -+The ``barebox,bootstate`` framework provides the building blocks to -+model different use cases without the need to start from the scratch -+over and over again. -+ -+The ``barebox,bootstate`` works on abstract boot targets, each with a -+set of properties and implements an algorithm which selects the -+highest priority target to boot. -+ -+A set of boot targets can be described in a devicetree node. This -+node could be part of the regular devicetree blob or it could be an -+extra devicetree for the bootstate. -+ -+A bootstate node contains a description of a set of boot targets along -+with a place where to store the mutable state. Currently implemented -+backends are :ref:`barebox,state` and ``nv`` (:ref:`command_nv`) -+variables. -+ -+Required properties: -+ -+* ``compatible``: should be ``barebox,bootstate``; -+* ``backend-type``: should be ``state`` or ``nv``. -+ -+Optional properties: -+ -+* ``backend``: phandle to the :ref:`barebox,state` backend -+ -+ -+boot target nodes - immutable description -+----------------------------------------- -+ -+These are subnodes of a bootstate node, each describing a boot -+target. The node name may end with ``@<ADDRESS>``, but the suffix is -+stripped from the target name. -+ -+Optional properties: -+ -+* ``default_attempts``: If the boot attempts counter is reset, this -+ value is used. -+ -+Example:: -+ -+ bootstate: bootstate { -+ compatible = "barebox,bootstate"; -+ backend-type = "state"; -+ backend = <&state>; -+ -+ system0 { -+ default_attempts = <3>; -+ }; -+ -+ system1 { -+ default_attempts = <3>; -+ }; -+ }; -+ -+In this example a bootstate, using a :ref:`barebox,state` backend with -+two boot target nodes ``system0`` and ``system1`` is defined. When the -+boot attempts counter is reset, the default value of ``3`` is used for -+both targets. -+ -+ -+boot target nodes - mutable state -+--------------------------------- -+ -+The above example uses a :ref:`barebox,state` backend, which requires -+some additional configuration to hold the mutable -+state. :ref:`barebox,state` has to be explicidly configured, while -+``nv`` (:ref:`command_nv`) variables are created on the fly. -+ -+The state of each boot target consists of the following ``uint32`` -+varibles: -+ -+* ``remaining_attempts``: holds the number of remaining boot attempts. -+ This variable is changed by the bootstate algorithm during boot. -+* ``priority``: defines the priority of the boot target. Higher number -+ indicate a higher priority, If two boot targets have the same -+ priority the one defined first in the device tree has precedence. -+ The ``priority`` can optionally be changed by the algorithm to 0, if -+ the boot target is decremented to ``0`` remaining boot attempts. A -+ ``priority`` of ``0`` means the boot target is **deactivated** and -+ will not be considered a valid target during further boots. If the -+ remaining attempts counter is reset, a target with priority 0 is -+ **not** changed. -+* ``ok``: this is an opaque value, it's not accessed by the bootstate -+ algorithm. It can be used be the Linux system to track the first -+ boot after an update. -+ -+The bootstate can also hold a default watchdog timeout (in seconds), -+which can be activated by the bootstate algorithm. -+ -+Example:: -+ -+ state: state { -+ magic = <0x4d433230>; -+ compatible = "barebox,state"; -+ backend-type = "raw"; -+ backend = <&backend_state>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ bootstate { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ system0 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ remaining_attempts { -+ reg = <0x0 0x4>; -+ type = "uint32"; -+ }; -+ priority { -+ reg = <0x4 0x4>; -+ type = "uint32"; -+ }; -+ ok { -+ reg = <0x8 0x4>; -+ type = "uint32"; -+ }; -+ }; -+ -+ system1 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ remaining_attempts { -+ reg = <0x10 0x4>; -+ type = "uint32"; -+ }; -+ priority { -+ reg = <0x14 0x4>; -+ type = "uint32"; -+ }; -+ ok { -+ reg = <0x18 0x4>; -+ type = "uint32"; -+ }; -+ }; -+ -+ watchdog_timeout { -+ reg = <0x20 0x4>; -+ type = "uint32"; -+ default = <60>; -+ }; -+ }; -+ }; -+ -+This example defines two boot targets (``system0`` and ``system1``) and -+a watchdog timeout of ``60`` seconds. -+ -+ -+Backends -+-------- -+ -+Currently two backends exist. The :ref:`barebox,state` backend is a -+bit more complicated to setup, as all boot target have to be described -+in the referenced :ref:`barebox,state` in the device tree. On the -+upside, the advantages of the (possible redundant storage, etc...) of -+the :ref:`barebox,state` is gained for free. -+ -+The :ref:`command_nv` backend is a lot simpler, no special setup is -+needed, it should run on every board, which already implements a -+read/writeable barebox environment. -+ -+ -+Algorithm -+--------- -+ -+The low level algorithm is implemented by the -+``bootstate_get_target()`` function. Its job is to iterate over all -+boot sources and return the name (as a string) of the choosen boot -+target. -+ -+The algorithm iterates over all boot targets defined under the -+associated device tree node and picks the one with the highest -+``priority`` (higher number have a higher priority) where the -+``remaining_attempts`` is greater than zero. A pointer to the name of -+the boot target is returned, the string should be freed via ``free()``. -+ -+The behaviour can be modified with the flags paramter. The following -+flags are currently supported: -+ -+* ``BOOTCHOOSER_FLAG_ATTEMPTS_KEEP``: the ``remaining_attempts`` -+ counter of the choosen boot target is not changed. -+* ``BOOTCHOOSER_FLAG_ATTEMPTS_DEC``: the ``remaining_attempts`` -+ counter of the choosen boot target is decremented by one. -+* ``BOOTCHOOSER_FLAG_ATTEMPTS_RESET``: the ``remaining_attempts`` -+ counter of all *active* boot targets (those with ``priority > 0``) -+ are reset to their default values as defined in the immutable -+ description by ``default_attempts``. -+* ``BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS``: if used together -+ with ``BOOTCHOOSER_FLAG_ATTEMPTS_DEC`` and the -+ ``remaining_attempts`` counter of the choosen boot target is -+ decremented to ``0``, the boot target is deactivated for further -+ boot attempts (although *this* boot is attemped as usual). This is -+ done by setting the ``priority`` to ``0``. -+* ``BOOTCHOOSER_FLAG_VERBOSE``: increases the verbosity of the output -+ -+ -+Frontend -+-------- -+ -+The shell command ``bootchooser`` (:ref:`command_bootchooser`) can be -+used to choose and start a boot target by a shell one-liner. The -+command picks the boot target with the highest priority and calls the -+``boot`` (:ref:`command_boot`) command with the selected boot target -+as its first and only parameter. -+ -+The ``bootchooser`` command implements command line paramter versions -+of the above described flags: -+ -+* ``-k``: keep boot attempts -+* ``-d``: decrement boot attempts -+* ``-r``: reset boot attempts -+* ``-z``: deactivate on zero remaining attempts -+* ``-v``: verbose output -+ -+Next to the standard parameters, these additional options are -+implemented: -+ -+* ``-D``: dryrun - do not boot (all other functionality is active) - a -+ specified watchdog timeout will be activated. -+* ``-R``: retry - if booting fails, then chose next target, but -+ decrement its attempts. Note: if the current target has still the -+ highest priority and remaining attemts, it will be selected again. -+* ``-w <TIMEOUT_IN_SEC>``: activate watchdog - if no parameter is -+ given, the timeout from the device tree is used. A given parameter -+ overwrites the device tree default. -diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts -index 2595aa13fa62..e2bc8f76c2e3 100644 ---- a/arch/sandbox/dts/sandbox.dts -+++ b/arch/sandbox/dts/sandbox.dts -@@ -3,5 +3,88 @@ - #include "skeleton.dtsi" - - / { -+ aliases { -+ state = &state; -+ }; - -+ state: state { -+ magic = <0x4d433230>; -+ compatible = "barebox,state"; -+ backend-type = "dtb"; -+ backend = "/fd0"; -+ -+ bootstate { -+ system0 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ remaining_attempts { -+ reg = <0x0 0x4>; -+ type = "uint32"; -+ }; -+ priority { -+ reg = <0x4 0x4>; -+ type = "uint32"; -+ }; -+ ok { -+ reg = <0x8 0x4>; -+ type = "uint32"; -+ }; -+ }; -+ -+ system1 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ remaining_attempts { -+ reg = <0x10 0x4>; -+ type = "uint32"; -+ }; -+ priority { -+ reg = <0x14 0x4>; -+ type = "uint32"; -+ }; -+ ok { -+ reg = <0x18 0x4>; -+ type = "uint32"; -+ }; -+ }; -+ -+ factory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ remaining_attempts { -+ reg = <0x20 0x4>; -+ type = "uint32"; -+ }; -+ priority { -+ reg = <0x24 0x4>; -+ type = "uint32"; -+ }; -+ ok { -+ reg = <0x28 0x4>; -+ type = "uint32"; -+ }; -+ }; -+ }; -+ }; -+ -+ bootstate: bootstate { -+ compatible = "barebox,bootstate"; -+ backend-type = "state"; // or "nv", or "efivar" -+ backend = <&state>; -+ -+ system0 { -+ default_attempts = <3>; -+ }; -+ -+ system1 { -+ default_attempts = <3>; -+ }; -+ -+ factory { -+ default_attempts = <3>; -+ }; -+ }; - }; -diff --git a/commands/Kconfig b/commands/Kconfig -index 875c5f4f01ed..603e887b15ec 100644 ---- a/commands/Kconfig -+++ b/commands/Kconfig -@@ -2189,6 +2189,11 @@ config CMD_SPD_DECODE - help - decode spd eeprom - -+config CMD_BOOTCHOOSER -+ tristate -+ depends on BOOTSTATE -+ prompt "bootchooser" -+ - # end Miscellaneous commands - endmenu - -diff --git a/commands/Makefile b/commands/Makefile -index f1b482f04934..bb3b40809af5 100644 ---- a/commands/Makefile -+++ b/commands/Makefile -@@ -117,3 +117,4 @@ obj-$(CONFIG_CMD_DHRYSTONE) += dhrystone.o - obj-$(CONFIG_CMD_SPD_DECODE) += spd_decode.o - obj-$(CONFIG_CMD_MMC_EXTCSD) += mmc_extcsd.o - obj-$(CONFIG_CMD_NAND_BITFLIP) += nand-bitflip.o -+obj-$(CONFIG_CMD_BOOTCHOOSER) += bootchooser.o -diff --git a/commands/bootchooser.c b/commands/bootchooser.c -new file mode 100644 -index 000000000000..06ca5e41d527 ---- /dev/null -+++ b/commands/bootchooser.c -@@ -0,0 +1,101 @@ -+/* -+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de> -+ * Copyright (C) 2015 Marc Kleine-Budde <mkl@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 <bootstate.h> -+#include <command.h> -+#include <common.h> -+#include <getopt.h> -+#include <malloc.h> -+#include <stdio.h> -+ -+static int do_bootchooser(int argc, char *argv[]) -+{ -+ unsigned flags = 0, timeout = 0; -+ char *name = NULL; -+ int opt, ret; -+ -+ while ((opt = getopt(argc, argv, "kdrzvDRw::")) > 0) { -+ switch (opt) { -+ case 'k': -+ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_KEEP; -+ break; -+ case 'd': -+ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_DEC; -+ break; -+ case 'r': -+ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_RESET; -+ break; -+ case 'z': -+ flags |= BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS; -+ break; -+ case 'v': -+ flags |= BOOTCHOOSER_FLAG_VERBOSE; -+ break; -+ case 'D': -+ flags |= BOOTCHOOSER_FLAG_DRYRUN; -+ break; -+ case 'R': -+ flags |= BOOTCHOOSER_FLAG_RETRY_WITH_DEC; -+ break; -+ case 'w': -+ if (optarg) -+ timeout = simple_strtoul(optarg, NULL, 0); -+ else -+ flags |= BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE; -+ flags |= BOOTCHOOSER_FLAG_WATCHDOG_ENABLE; -+ break; -+ default: -+ return COMMAND_ERROR_USAGE; -+ } -+ } -+ -+ if (optind < argc) -+ name = argv[optind]; -+ -+ if (!(flags & (BOOTCHOOSER_FLAG_ATTEMPTS_KEEP | -+ BOOTCHOOSER_FLAG_ATTEMPTS_DEC | -+ BOOTCHOOSER_FLAG_ATTEMPTS_RESET))) { -+ bootstate_info(); -+ return 0; -+ } -+ -+ if ((flags & BOOTCHOOSER_FLAG_ATTEMPTS_KEEP) && -+ (flags & (BOOTCHOOSER_FLAG_ATTEMPTS_DEC | BOOTCHOOSER_FLAG_ATTEMPTS_RESET))) -+ return COMMAND_ERROR_USAGE; -+ -+ ret = bootstate_bootchooser(name, flags, timeout); -+ -+ return ret ? COMMAND_ERROR : COMMAND_SUCCESS; -+} -+ -+BAREBOX_CMD_HELP_START(bootchooser) -+BAREBOX_CMD_HELP_TEXT("Options:") -+BAREBOX_CMD_HELP_OPT ("-k","keep - boot, don't modify attempts counter") -+BAREBOX_CMD_HELP_OPT ("-d","decrement - boot, but decrement attempts counter by one") -+BAREBOX_CMD_HELP_OPT ("-r","reset - boot, but reset _all_ attempts counters to default") -+BAREBOX_CMD_HELP_OPT ("-z","deactivate chosen target on zero remaining boot attempts") -+BAREBOX_CMD_HELP_OPT ("-v","verbose output") -+BAREBOX_CMD_HELP_OPT ("-D","dryrun - do not boot, but handle watchdog and reset") -+BAREBOX_CMD_HELP_OPT ("-R","retry - boot, retry next boot target and decrement attempts") -+BAREBOX_CMD_HELP_OPT ("-w","activate watchdog, use timeout specified in <BOOTSTATE>.watchdog_timeout") -+BAREBOX_CMD_HELP_END -+ -+BAREBOX_CMD_START(bootchooser) -+ .cmd = do_bootchooser, -+ BAREBOX_CMD_DESC("automatically select a boot target and boot") -+ BAREBOX_CMD_OPTS("[-kdrzvDR] -w <TIMEOUT> [BOOTSTATE]") -+ BAREBOX_CMD_GROUP(CMD_GRP_MISC) -+ BAREBOX_CMD_HELP(cmd_bootchooser_help) -+BAREBOX_CMD_END -diff --git a/common/Kconfig b/common/Kconfig -index 7c09e8c117f1..f17769661ee6 100644 ---- a/common/Kconfig -+++ b/common/Kconfig -@@ -792,6 +792,14 @@ config STATE_CRYPTO - See Documentation/devicetree/bindings/barebox/barebox,state.rst - for more information. - -+config BOOTSTATE -+ bool "bootstate infrastructure" -+ depends on OF_BAREBOX_DRIVERS -+ select ENVIRONMENT_VARIABLES -+ select OFTREE -+ select PARAMETER -+ select BOOTSTATE_DRV -+ - config RESET_SOURCE - bool "detect Reset cause" - depends on GLOBALVAR -diff --git a/common/Makefile b/common/Makefile -index d99ca7b7ac74..5505449874ad 100644 ---- a/common/Makefile -+++ b/common/Makefile -@@ -46,6 +46,7 @@ obj-$(CONFIG_SHELL_HUSH) += hush.o - obj-$(CONFIG_SHELL_SIMPLE) += parser.o - obj-$(CONFIG_STATE) += state.o - obj-$(CONFIG_RATP) += ratp.o -+obj-$(CONFIG_BOOTSTATE) += bootstate.o - obj-$(CONFIG_UIMAGE) += image.o uimage.o - obj-$(CONFIG_FITIMAGE) += image-fit.o - obj-$(CONFIG_MENUTREE) += menutree.o -diff --git a/common/bootstate.c b/common/bootstate.c -new file mode 100644 -index 000000000000..3dc18813064d ---- /dev/null -+++ b/common/bootstate.c -@@ -0,0 +1,781 @@ -+/* -+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de> -+ * Copyright (C) 2015 Marc Kleine-Budde <mkl@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 <bootstate.h> -+#include <common.h> -+#include <envfs.h> -+#include <environment.h> -+#include <errno.h> -+#include <fcntl.h> -+#include <fs.h> -+#include <globalvar.h> -+#include <init.h> -+#include <ioctl.h> -+#include <libbb.h> -+#include <libfile.h> -+#include <malloc.h> -+#include <net.h> -+#include <printk.h> -+#include <state.h> -+#include <stdio.h> -+#include <watchdog.h> -+#include <xfuncs.h> -+ -+#include <linux/err.h> -+#include <linux/kernel.h> -+#include <linux/list.h> -+#include <linux/mtd/mtd-abi.h> -+#include <linux/mtd/mtd.h> -+ -+#include <asm/unaligned.h> -+ -+/* list of all registered bootstate instances */ -+static LIST_HEAD(bootstate_list); -+ -+struct state_backend; -+ -+struct bootstate { -+ struct device_d dev; -+ const char *name; -+ struct list_head list; -+ struct list_head targets; -+ struct list_head targets_unsorted; -+ struct bootstate_backend *backend; -+ bool dirty; -+}; -+ -+struct bootstate_backend { -+ int (*load)(struct bootstate_backend *backend, struct bootstate *bootstate); -+ int (*save)(struct bootstate_backend *backend, struct bootstate *bootstate); -+ const char *name; -+ const char *path; -+}; -+ -+struct bootstate_target { -+ struct list_head list; -+ struct list_head list_unsorted; -+ -+ /* state */ -+ unsigned int priority; -+ unsigned int remaining_attempts; -+ bool ok; -+ -+ /* spec */ -+ const char *name; -+ unsigned int default_attempts; -+}; -+ -+static void pr_target(struct bootstate *bootstate, struct bootstate_target *target) -+{ -+ printf("%s: target: name=%s prio=%u, ok=%d, rem=%u, def=%u\n", -+ bootstate->name, target->name, target->priority, target->ok, -+ target->remaining_attempts, target->default_attempts); -+} -+ -+static struct bootstate *bootstate_new(const char *name) -+{ -+ struct bootstate *bootstate; -+ int ret; -+ -+ bootstate = xzalloc(sizeof(*bootstate)); -+ safe_strncpy(bootstate->dev.name, name, MAX_DRIVER_NAME); -+ bootstate->name = bootstate->dev.name; -+ bootstate->dev.id = DEVICE_ID_DYNAMIC; -+ INIT_LIST_HEAD(&bootstate->targets); -+ INIT_LIST_HEAD(&bootstate->targets_unsorted); -+ -+ ret = register_device(&bootstate->dev); -+ if (ret) { -+ free(bootstate); -+ return ERR_PTR(ret); -+ } -+ -+ list_add_tail(&bootstate->list, &bootstate_list); -+ -+ return bootstate; -+} -+ -+void bootstate_release(struct bootstate *bootstate) -+{ -+ list_del(&bootstate->list); -+ unregister_device(&bootstate->dev); -+ free(bootstate); -+} -+ -+static int bootstate_target_compare(struct list_head *a, struct list_head *b) -+{ -+ struct bootstate_target *bootstate_a = list_entry(a, struct bootstate_target, list); -+ struct bootstate_target *bootstate_b = list_entry(b, struct bootstate_target, list); -+ -+ /* order descending */ -+ return bootstate_a->priority >= bootstate_b->priority ? -1 : 1; -+} -+ -+static void bootstate_target_add(struct bootstate *bootstate, struct bootstate_target *target) -+{ -+ list_del(&target->list); -+ list_add_sort(&target->list, &bootstate->targets, bootstate_target_compare); -+} -+ -+static int bootstate_variable_read_u32(const struct bootstate *bootstate, -+ const char *name, uint32_t *out_val) -+{ -+ char *var; -+ int ret; -+ -+ var = asprintf("%s.%s.%s", bootstate->backend->path, bootstate->name, name); -+ ret = getenv_uint(var, out_val); -+ free(var); -+ -+ return ret; -+} -+ -+static int bootstate_backend_variable_read_target_u32(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate, -+ const struct bootstate_target *target, -+ const char *name, uint32_t *out_val) -+{ -+ char *var; -+ int ret; -+ -+ var = asprintf("%s.%s.%s.%s", backend->path, bootstate->name, -+ target->name, name); -+ ret = getenv_uint(var, out_val); -+ free(var); -+ -+ return ret; -+} -+ -+static int bootstate_backend_variable_write_target_u32(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate, -+ const struct bootstate_target *target, -+ const char *name, uint32_t in_val) -+{ -+ char *var; -+ char *val; -+ int ret; -+ -+ var = asprintf("%s.%s.%s.%s", backend->path, bootstate->name, -+ target->name, name); -+ val = asprintf("%d", in_val); -+ ret = setenv(var, val); -+ free(val); -+ free(var); -+ -+ return ret; -+} -+ -+static int bootstate_variable_nv_init_u32(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate, -+ const struct bootstate_target *target, -+ const char *name) -+{ -+ char *var; -+ int ret; -+ -+ var = asprintf("%s.%s.%s", bootstate->name, target->name, name); -+ ret = nvvar_add(var, "0"); -+ free(var); -+ -+ return ret; -+} -+ -+static struct bootstate_target *bootstate_target_find(const struct bootstate *bootstate, -+ const char *name) -+{ -+ struct bootstate_target *target; -+ -+ list_for_each_entry(target, &bootstate->targets, list) { -+ if (!strcmp(target->name, name)) -+ return target; -+ } -+ -+ return ERR_PTR(-ENOENT); -+} -+ -+static int bootstate_target_from_node(struct bootstate *bootstate, const struct device_node *node, bool create) -+{ -+ struct bootstate_target *target; -+ char *name, *indexs; -+ int ret; -+ -+ name = xstrdup(node->name); -+ indexs = strchr(name, '@'); -+ if (indexs) -+ *indexs++ = 0; -+ -+ if (create) { -+ /* create*/ -+ target = xzalloc(sizeof(*target)); -+ -+ target->name = xstrdup(name); -+ list_add_tail(&target->list, &bootstate->targets); -+ list_add_tail(&target->list_unsorted, -+ &bootstate->targets_unsorted); -+ } else { -+ target = bootstate_target_find(bootstate, name); -+ if (IS_ERR(target)) { -+ int ret = PTR_ERR(target); -+ pr_err("no such boot target: %s: %s\n", -+ name, strerror(-ret)); -+ return ret; -+ } -+ } -+ -+ /* init */ -+ ret = of_property_read_u32(node, "default_attempts", -+ &target->default_attempts); -+ if (ret) -+ return ret; -+ -+ free(name); -+ -+ return 0; -+} -+ -+static int bootstate_from_node(struct bootstate *bootstate, -+ const struct device_node *node, bool create) -+{ -+ struct device_node *child; -+ int ret; -+ -+ for_each_child_of_node(node, child) { -+ ret = bootstate_target_from_node(bootstate, child, create); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int bootstate_backend_load_one(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate, -+ struct bootstate_target *target) -+{ -+ uint32_t tmp; -+ int ret; -+ -+ ret = bootstate_backend_variable_read_target_u32(backend, bootstate, target, -+ "remaining_attempts", -+ &target->remaining_attempts); -+ if (ret) -+ return ret; -+ -+ ret = bootstate_backend_variable_read_target_u32(backend, bootstate, target, -+ "priority", &target->priority); -+ if (ret) -+ return ret; -+ -+ ret = bootstate_backend_variable_read_target_u32(backend, bootstate, target, -+ "ok", &tmp); -+ if (ret) -+ return ret; -+ -+ target->ok = !!tmp; -+ -+ return ret; -+} -+ -+static int bootstate_backend_load(struct bootstate_backend *backend, -+ struct bootstate *bootstate) -+{ -+ struct bootstate_target *target; -+ int ret; -+ -+ list_for_each_entry(target, &bootstate->targets_unsorted, list_unsorted) { -+ ret = bootstate_backend_load_one(backend, bootstate, target); -+ if (ret) -+ return ret; -+ bootstate_target_add(bootstate, target); -+ } -+ -+ return 0; -+} -+ -+static int bootstate_backend_save_one(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate, -+ struct bootstate_target *target) -+{ -+ int ret; -+ -+ ret = bootstate_backend_variable_write_target_u32(backend, bootstate, target, -+ "remaining_attempts", -+ target->remaining_attempts); -+ if (ret) -+ return ret; -+ -+ ret = bootstate_backend_variable_write_target_u32(backend, bootstate, target, -+ "priority", target->priority); -+ if (ret) -+ return ret; -+ -+ ret = bootstate_backend_variable_write_target_u32(backend, bootstate, target, -+ "ok", target->ok); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int bootstate_backend_save(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate) -+{ -+ struct bootstate_target *target; -+ int ret; -+ -+ list_for_each_entry(target, &bootstate->targets, list) { -+ ret = bootstate_backend_save_one(backend, bootstate, target); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int bootstate_backend_nv_init_one(const struct bootstate_backend *backend, -+ const struct bootstate *bootstate, -+ struct bootstate_target *target) -+{ -+ int ret; -+ -+ ret = bootstate_variable_nv_init_u32(backend, bootstate, target, -+ "remaining_attempts"); -+ if (ret) -+ return ret; -+ -+ ret = bootstate_variable_nv_init_u32(backend, bootstate, target, -+ "priority"); -+ if (ret) -+ return ret; -+ -+ ret = bootstate_variable_nv_init_u32(backend, bootstate, target, -+ "ok"); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int bootstate_backend_nv_init(struct bootstate_backend *backend, -+ struct bootstate *bootstate) -+{ -+ struct bootstate_target *target; -+ int ret; -+ -+ list_for_each_entry(target, &bootstate->targets_unsorted, list_unsorted) { -+ ret = bootstate_backend_nv_init_one(backend, bootstate, target); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int bootstate_backend_nv_save(struct bootstate_backend *backend, -+ struct bootstate *bootstate) -+{ -+ int ret; -+ -+ ret = bootstate_backend_save(backend, bootstate); -+ if (ret) -+ return ret; -+ -+ return envfs_save(NULL, NULL, 0); -+} -+ -+static int bootstate_backend_nv_load(struct bootstate_backend *backend, -+ struct bootstate *bootstate) -+{ -+ return bootstate_backend_load(backend, bootstate); -+} -+ -+struct bootstate_backend_nv { -+ struct bootstate_backend backend; -+}; -+ -+int bootstate_backend_nv(struct bootstate *bootstate) -+{ -+ struct bootstate_backend_nv *backend_nv; -+ struct bootstate_backend *backend; -+ -+ if (bootstate->backend) -+ return -EBUSY; -+ -+ backend_nv = xzalloc(sizeof(*backend_nv)); -+ backend = &backend_nv->backend; -+ -+ backend->load = bootstate_backend_nv_load; -+ backend->save = bootstate_backend_nv_save; -+ backend->name = "nv"; -+ backend->path = "nv"; -+ -+ bootstate->backend = backend; -+ -+ return bootstate_backend_nv_init(backend, bootstate); -+} -+ -+struct bootstate_backend_state { -+ struct bootstate_backend backend; -+ struct state *state; -+}; -+ -+static int bootstate_backend_state_save(struct bootstate_backend *backend, -+ struct bootstate *bootstate) -+{ -+ struct bootstate_backend_state *backend_state = -+ container_of(backend, struct bootstate_backend_state, backend); -+ int ret; -+ -+ ret = bootstate_backend_save(backend, bootstate); -+ if (ret) -+ return ret; -+ -+ return state_save(backend_state->state); -+} -+ -+static int bootstate_backend_state_load(struct bootstate_backend *backend, -+ struct bootstate *bootstate) -+{ -+ return bootstate_backend_load(backend, bootstate); -+} -+ -+int bootstate_backend_state(struct bootstate *bootstate, const struct device_node *node) -+{ -+ struct bootstate_backend_state *backend_state; -+ struct bootstate_backend *backend; -+ const struct device_node *state_node; -+ struct state *state; -+ -+ if (bootstate->backend) -+ return -EBUSY; -+ -+ state_node = of_parse_phandle(node, "backend", 0); -+ if (!state_node) -+ return -EINVAL; -+ -+ state = state_by_node(state_node); -+ if (!state) -+ return -EPROBE_DEFER; -+ -+ backend_state = xzalloc(sizeof(*backend_state)); -+ backend_state->state = state; -+ -+ backend = &backend_state->backend; -+ backend->load = bootstate_backend_state_load; -+ backend->save = bootstate_backend_state_save; -+ backend->name = "state"; -+ -+ bootstate->backend = backend; -+ -+ return state_get_name(backend_state->state, &backend->path); -+} -+ -+/* -+ * bootstate_new_from_node - create a new bootstate instance from a device_node -+ * -+ * @name The name of the new bootstate instance -+ * @node The device_node describing the new bootstate instance -+ */ -+struct bootstate *bootstate_new_from_node(const char *name, const struct device_node *node) -+{ -+ struct bootstate *bootstate; -+ int ret; -+ -+ pr_debug("%s: node=%s, name=%s\n", __func__, node->full_name, name); -+ -+ bootstate = bootstate_new(name); -+ if (!bootstate) -+ return ERR_PTR(-EINVAL); -+ -+ ret = bootstate_from_node(bootstate, node, true); -+ if (ret) { -+ bootstate_release(bootstate); -+ return ERR_PTR(ret); -+ } -+ -+ return bootstate; -+} -+ -+/* -+ * bootstate_by_name - find a bootstate instance by name -+ * -+ * @name The name of the state instance -+ */ -+struct bootstate *bootstate_by_name(const char *name) -+{ -+ struct bootstate *bs; -+ -+ list_for_each_entry(bs, &bootstate_list, list) { -+ if (!strcmp(name, bs->name)) -+ return bs; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * bootstate_load - load a bootstate from the backing store -+ * -+ * @bootstate The state instance to load -+ */ -+static int bootstate_load(struct bootstate *bootstate) -+{ -+ int ret; -+ -+ if (!bootstate->backend) -+ return -ENOSYS; -+ -+ ret = bootstate->backend->load(bootstate->backend, bootstate); -+ if (ret) -+ bootstate->dirty = 1; -+ else -+ bootstate->dirty = 0; -+ -+ return ret; -+} -+ -+/* -+ * bootstate_save - save a bootstate to the backing store -+ * -+ * @bootstate The bootstate instance to save -+ */ -+static int bootstate_save(struct bootstate *bootstate) -+{ -+ int ret; -+ -+ if (!bootstate->dirty) -+ return 0; -+ -+ if (!bootstate->backend) -+ return -ENOSYS; -+ -+ ret = bootstate->backend->save(bootstate->backend, bootstate); -+ if (ret) -+ return ret; -+ -+ bootstate->dirty = 0; -+ -+ return 0; -+} -+ -+void bootstate_info(void) -+{ -+ struct bootstate *bootstate; -+ -+ printf("registered bootstate instances:\n"); -+ -+ list_for_each_entry(bootstate, &bootstate_list, list) { -+ printf("%-20s ", bootstate->name); -+ printf("(backend: %s, path: %s)\n", -+ bootstate->backend->name, bootstate->backend->path); -+ } -+} -+ -+#define __BF(arg) [__BOOTCHOOSER_FLAG_##arg##_SHIFT] = __stringify(arg) -+ -+static const char * const bootstate_flags_str[] = { -+ __BF(ATTEMPTS_KEEP), -+ __BF(ATTEMPTS_DEC), -+ __BF(ATTEMPTS_RESET), -+ __BF(DEACTIVATE_ON_ZERO_ATTEMPTS), -+ __BF(VERBOSE), -+ __BF(DRYRUN), -+ __BF(RETRY_WITH_DEC), -+ __BF(WATCHDOG_ENABLE), -+ __BF(WATCHDOG_TIMEOUT_FROM_STATE), -+}; -+ -+#undef __BF -+ -+#define pr(verbose, format, args...) \ -+ ({ \ -+ (verbose) ? pr_info((format), ##args) : 0; \ -+ }) -+ -+void _pr_flags(struct bootstate *bootstate, unsigned flags) -+{ -+ int i; -+ -+ pr_info("%s: flags=0x%08x\n", bootstate->name, flags); -+ -+ for (i = 0; i < ARRAY_SIZE(bootstate_flags_str); i++) { -+ if (flags & (1 << i)) -+ pr_info("%s: -> %s\n", bootstate->name, -+ bootstate_flags_str[i]); -+ } -+} -+ -+#define pr_flags(verbose, bootstate, flags) \ -+ ({ \ -+ (verbose) ? _pr_flags(bootstate, flags) : 0; \ -+ }) -+ -+/* -+ * bootstate_get_target - create a new state instance from a device_node -+ * -+ * @bootstate the bootstate instance to work in -+ * @flags supported flags: -+ * BOOTCHOOSER_FLAG_VERBOSE -+ * BOOTCHOOSER_FLAG_ATTEMPTS_KEEP -+ * BOOTCHOOSER_FLAG_ATTEMPTS_DEC -+ * BOOTCHOOSER_FLAG_ATTEMPTS_RESET -+ * BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS -+ * @target_out a string to the choosen boot target is returned via -+ * this paramater -+ */ -+int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **target_out) -+{ -+ struct bootstate_target *target; -+ int ret; -+ bool found = false; -+ bool v = flags & BOOTCHOOSER_FLAG_VERBOSE; -+ -+ pr_flags(v, bootstate, flags); -+ -+ ret = bootstate_load(bootstate); -+ if (ret) -+ return ret; -+ -+ if (flags & BOOTCHOOSER_FLAG_ATTEMPTS_RESET) { -+ list_for_each_entry(target, &bootstate->targets, list) { -+ if (target->priority == 0) -+ continue; -+ -+ target->remaining_attempts = target->default_attempts; -+ bootstate->dirty = true; -+ -+ pr(v, "%s: target: name=%s setting rem to %d due to %s\n", -+ bootstate->name, target->name, target->default_attempts, -+ bootstate_flags_str[__BOOTCHOOSER_FLAG_ATTEMPTS_RESET_SHIFT]); -+ } -+ pr(v, "%s: --------\n", bootstate->name); -+ } -+ -+ list_for_each_entry(target, &bootstate->targets, list) { -+ pr_target(bootstate, target); -+ -+ if (found) -+ continue; -+ -+ if (target->priority == 0) { -+ pr(v, "%s: name=%s prio=%d - trying next\n", -+ bootstate->name, target->name, target->priority); -+ continue; -+ } -+ -+ if (target->remaining_attempts == 0) { -+ pr(v, "%s: name=%s remaining attempts == 0 - trying next\n", -+ bootstate->name, target->name); -+ continue; -+ } -+ -+ if (flags & BOOTCHOOSER_FLAG_ATTEMPTS_DEC) { -+ bootstate->dirty = true; -+ target->remaining_attempts--; -+ -+ pr(v, "%s: name=%s decrementing remaining_attempts to %d due to %s\n", -+ bootstate->name, target->name, -+ target->remaining_attempts, -+ bootstate_flags_str[__BOOTCHOOSER_FLAG_ATTEMPTS_DEC_SHIFT]); -+ -+ if ((target->remaining_attempts == 0) && -+ (flags & BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS)) { -+ target->priority = 0; -+ -+ pr(v, "%s: name=%s deactivating target (setting priority = 0) due to %s\n", -+ bootstate->name, target->name, -+ bootstate_flags_str[__BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS_SHIFT]); -+ } -+ } -+ -+ found = true; -+ *target_out = strdup(target->name); -+ pr_debug("%s: selected target '%s'\n", __func__, target->name); -+ if (!v) -+ goto out; -+ -+ pr(v, "%s: --- other bootsources ---\n", bootstate->name); -+ } -+ -+ out: -+ bootstate_save(bootstate); -+ -+ if (!found) -+ return -ENOENT; -+ -+ return 0; -+} -+ -+int bootstate_bootchooser(char *name, unsigned flags, unsigned timeout) -+{ -+ struct bootstate *bootstate; -+ bool v = flags & BOOTCHOOSER_FLAG_VERBOSE; -+ char *target; -+ int ret; -+ -+ if (!name) -+ name = "bootstate"; -+ -+ bootstate = bootstate_by_name(name); -+ if (!bootstate) { -+ pr_err("Bootstate '%s' not found.\n", name); -+ return -ENODEV; -+ } -+ -+ if (flags & BOOTCHOOSER_FLAG_WATCHDOG_ENABLE) { -+ if (flags & BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE) { -+ ret = bootstate_variable_read_u32(bootstate, "watchdog_timeout", -+ &timeout); -+ if (ret) -+ return ret; -+ } -+ -+ if (timeout != 0) { -+ pr(v, "%s: starting watchdog with timeout=%ds\n", -+ __func__, timeout); -+ -+ ret = watchdog_set_timeout(timeout); -+ if (ret) -+ return ret; -+ } -+ } -+ -+ while (true) { -+ char *cmd; -+ -+ ret = bootstate_get_target(bootstate, flags, &target); -+ if (ret) -+ return ret; -+ -+ cmd = asprintf("boot %s", target); -+ free(target); -+ pr_info("%srunning: %s...\n", -+ flags & BOOTCHOOSER_FLAG_DRYRUN ? "not " : "", cmd); -+ if (!(flags & BOOTCHOOSER_FLAG_DRYRUN)) -+ ret = run_command(cmd); -+ free(cmd); -+ -+ if (flags & BOOTCHOOSER_FLAG_RETRY_WITH_DEC) { -+ flags |= BOOTCHOOSER_FLAG_ATTEMPTS_DEC; -+ flags &= ~(BOOTCHOOSER_FLAG_ATTEMPTS_RESET | -+ BOOTCHOOSER_FLAG_ATTEMPTS_KEEP); -+ continue; -+ } -+ -+ return ret; -+ } -+ -+ return -ENOENT; -+} -diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 7a5b14697efd..2459051e1db1 100644 ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -19,4 +19,9 @@ config STATE_DRV - tristate "state driver" - depends on STATE - -+config BOOTSTATE_DRV -+ tristate "bootstate driver" -+ depends on BOOTSTATE -+ depends on STATE -+ - endmenu -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index 487e4b8ba2e5..603e14ebb5de 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -5,3 +5,4 @@ - obj-$(CONFIG_JTAG) += jtag.o - obj-$(CONFIG_SRAM) += sram.o - obj-$(CONFIG_STATE_DRV) += state.o -+obj-$(CONFIG_BOOTSTATE_DRV) += bootstate.o -diff --git a/drivers/misc/bootstate.c b/drivers/misc/bootstate.c -new file mode 100644 -index 000000000000..3ec9b8fda86b ---- /dev/null -+++ b/drivers/misc/bootstate.c -@@ -0,0 +1,79 @@ -+/* -+ * Copyright (C) 2013 Sascha Hauer <s.hauer@pengutronix.de> -+ * Copyright (C) 2015 Marc Kleine-Budde <mkl@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 <bootstate.h> -+#include <driver.h> -+#include <init.h> -+#include <malloc.h> -+#include <of.h> -+#include <printk.h> -+#include <string.h> -+ -+#include <linux/err.h> -+ -+static int bootstate_probe(struct device_d *dev) -+{ -+ struct device_node *np = dev->device_node; -+ struct bootstate *bootstate; -+ const char *alias; -+ const char *backend_type = NULL; -+ int ret; -+ -+ if (!np) -+ return -EINVAL; -+ -+ alias = of_alias_get(np); -+ if (!alias) -+ alias = "bootstate"; -+ -+ bootstate = bootstate_new_from_node(alias, np); -+ if (IS_ERR(bootstate)) -+ return PTR_ERR(bootstate); -+ -+ of_property_read_string(np, "backend-type", &backend_type); -+ if (!strcmp(backend_type, "state")) { -+ ret = bootstate_backend_state(bootstate, np); -+ } else if (!strcmp(backend_type, "nv")) { -+ ret = bootstate_backend_nv(bootstate); -+ } else { -+ dev_warn(dev, "invalid backend type: %s\n", backend_type); -+ ret = -ENODEV; -+ goto out_release; -+ } -+ -+ if (ret) -+ goto out_release; -+ -+ return 0; -+ -+ out_release: -+ bootstate_release(bootstate); -+ return ret; -+} -+ -+static __maybe_unused struct of_device_id bootstate_ids[] = { -+ { -+ .compatible = "barebox,bootstate", -+ }, { -+ /* sentinel */ -+ } -+}; -+ -+static struct driver_d bootstate_driver = { -+ .name = "bootstate", -+ .probe = bootstate_probe, -+ .of_compatible = DRV_OF_COMPAT(bootstate_ids), -+}; -+device_platform_driver(bootstate_driver); -diff --git a/include/bootstate.h b/include/bootstate.h -new file mode 100644 -index 000000000000..22631c902f60 ---- /dev/null -+++ b/include/bootstate.h -@@ -0,0 +1,39 @@ -+#ifndef __BOOTSTATE_H -+#define __BOOTSTATE_H -+ -+#include <of.h> -+ -+struct bootstate *bootstate_new_from_node(const char *name, const struct device_node *node); -+struct bootstate *bootstate_find_by_name(const char *name); -+struct bootstate *bootstate_by_name(const char *name); -+void bootstate_release(struct bootstate *bootstate); -+void bootstate_info(void); -+int bootstate_backend_nv(struct bootstate *bootstate); -+int bootstate_backend_state(struct bootstate *bootstate, const struct device_node *node); -+ -+enum { -+ __BOOTCHOOSER_FLAG_ATTEMPTS_KEEP_SHIFT, -+ __BOOTCHOOSER_FLAG_ATTEMPTS_DEC_SHIFT, -+ __BOOTCHOOSER_FLAG_ATTEMPTS_RESET_SHIFT, -+ __BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS_SHIFT, -+ __BOOTCHOOSER_FLAG_VERBOSE_SHIFT, -+ __BOOTCHOOSER_FLAG_DRYRUN_SHIFT, -+ __BOOTCHOOSER_FLAG_RETRY_WITH_DEC_SHIFT, -+ __BOOTCHOOSER_FLAG_WATCHDOG_ENABLE_SHIFT, -+ __BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE_SHIFT, -+}; -+ -+#define BOOTCHOOSER_FLAG_ATTEMPTS_KEEP (1 << __BOOTCHOOSER_FLAG_ATTEMPTS_KEEP_SHIFT) -+#define BOOTCHOOSER_FLAG_ATTEMPTS_DEC (1 << __BOOTCHOOSER_FLAG_ATTEMPTS_DEC_SHIFT) -+#define BOOTCHOOSER_FLAG_ATTEMPTS_RESET (1 << __BOOTCHOOSER_FLAG_ATTEMPTS_RESET_SHIFT) -+#define BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS (1 << __BOOTCHOOSER_FLAG_DEACTIVATE_ON_ZERO_ATTEMPTS_SHIFT) -+#define BOOTCHOOSER_FLAG_VERBOSE (1 << __BOOTCHOOSER_FLAG_VERBOSE_SHIFT) -+#define BOOTCHOOSER_FLAG_DRYRUN (1 << __BOOTCHOOSER_FLAG_DRYRUN_SHIFT) -+#define BOOTCHOOSER_FLAG_RETRY_WITH_DEC (1 << __BOOTCHOOSER_FLAG_RETRY_WITH_DEC_SHIFT) -+#define BOOTCHOOSER_FLAG_WATCHDOG_ENABLE (1 << __BOOTCHOOSER_FLAG_WATCHDOG_ENABLE_SHIFT) -+#define BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE (1 << __BOOTCHOOSER_FLAG_WATCHDOG_TIMEOUT_FROM_STATE_SHIFT) -+ -+int bootstate_get_target(struct bootstate *bootstate, unsigned flags, char **target_out); -+int bootstate_bootchooser(char *name, unsigned flags, unsigned watchdog_timeout_s); -+ -+#endif /* __BOOTSTATE_H */ |