/src/barebox/common/restart.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-only |
2 | | /* |
3 | | * Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix |
4 | | */ |
5 | | #define pr_fmt(fmt) "restart: " fmt |
6 | | |
7 | | #include <common.h> |
8 | | #include <restart.h> |
9 | | #include <malloc.h> |
10 | | #include <asm/sections.h> |
11 | | #include <efi/types.h> |
12 | | #include <of.h> |
13 | | |
14 | | static LIST_HEAD(restart_handler_list); |
15 | | static unsigned resetidx; |
16 | | |
17 | | static __efi_runtime_data void (*rt_restart)(unsigned long flags); |
18 | | static int rt_restart_prio = INT_MIN; |
19 | | static __efi_runtime_data void (*rt_restart_warm)(unsigned long flags); |
20 | | static int rt_restart_warm_prio = INT_MIN; |
21 | | |
22 | | static void rt_restart_handler_register(struct restart_handler *handler) |
23 | 78 | { |
24 | 78 | if (!IS_ENABLED(CONFIG_EFI_RUNTIME)) |
25 | 78 | return; |
26 | 0 | if (!handler->rt_restart) |
27 | 0 | return; |
28 | 0 | if (!in_barebox_efi_runtime((ulong)handler->rt_restart)) { |
29 | | /* Check if __efi_runtime attribute is missing */ |
30 | 0 | pr_warn("handler outside EFI runtime section\n"); |
31 | 0 | return; |
32 | 0 | } |
33 | | |
34 | 0 | if (handler->priority > rt_restart_prio) { |
35 | 0 | rt_restart = handler->rt_restart; |
36 | 0 | rt_restart_prio = handler->priority; |
37 | 0 | } |
38 | |
|
39 | 0 | if (handler->priority > rt_restart_warm_prio && |
40 | 0 | handler->flags & RESTART_WARM) { |
41 | 0 | rt_restart_warm = handler->rt_restart; |
42 | 0 | rt_restart_warm_prio = handler->priority; |
43 | 0 | } |
44 | 0 | } |
45 | | |
46 | | /** |
47 | | * restart_handler_register() - register a handler for restarting the system |
48 | | * @rst: The handler struct |
49 | | * |
50 | | * This adds @rst to the list of registered restart handlers. |
51 | | * |
52 | | * return: 0 for success or negative error code |
53 | | */ |
54 | | int restart_handler_register(struct restart_handler *rst) |
55 | 78 | { |
56 | 78 | if (!rst->name) |
57 | 0 | rst->name = basprintf("reset%u", resetidx); |
58 | 78 | if (!rst->priority) |
59 | 26 | rst->priority = RESTART_DEFAULT_PRIORITY; |
60 | | |
61 | 78 | if (rst->of_node) { |
62 | 0 | of_property_read_u32(rst->of_node, "restart-priority", |
63 | 0 | &rst->priority); |
64 | 0 | if (of_property_read_bool(rst->of_node, |
65 | 0 | "barebox,restart-warm-bootrom")) |
66 | 0 | rst->flags |= RESTART_WARM; |
67 | 0 | } |
68 | | |
69 | 78 | rt_restart_handler_register(rst); |
70 | | |
71 | 78 | list_add_tail(&rst->list, &restart_handler_list); |
72 | | |
73 | 78 | pr_debug("registering restart handler \"%s\" with priority %d\n", |
74 | 78 | rst->name, rst->priority); |
75 | | |
76 | 78 | resetidx++; |
77 | 78 | return 0; |
78 | 78 | } |
79 | | |
80 | | /** |
81 | | * restart_handler_register_fn() - register a handler function |
82 | | * @name: restart method name or NULL if name should be auto-generated |
83 | | * @restart_fn: The restart function |
84 | | * |
85 | | * convenience wrapper for restart_handler_register() to register a handler |
86 | | * with given function and default values otherwise. |
87 | | * |
88 | | * return: 0 for success or negative error code |
89 | | */ |
90 | | int restart_handler_register_fn(const char *name, |
91 | | void (*restart_fn)(struct restart_handler *, |
92 | | unsigned long flags)) |
93 | 0 | { |
94 | 0 | struct restart_handler *rst; |
95 | 0 | int ret; |
96 | |
|
97 | 0 | rst = xzalloc(sizeof(*rst)); |
98 | |
|
99 | 0 | rst->name = xstrdup_const(name); |
100 | 0 | rst->restart = restart_fn; |
101 | |
|
102 | 0 | ret = restart_handler_register(rst); |
103 | |
|
104 | 0 | if (ret) |
105 | 0 | free(rst); |
106 | |
|
107 | 0 | return ret; |
108 | 0 | } |
109 | | |
110 | | /** |
111 | | * restart_handler_get_by_name() - get highest priority `name' |
112 | | */ |
113 | | struct restart_handler *restart_handler_get_by_name(const char *name, int flags) |
114 | 0 | { |
115 | 0 | struct restart_handler *rst = NULL, *tmp; |
116 | 0 | unsigned int priority = 0; |
117 | |
|
118 | 0 | list_for_each_entry(tmp, &restart_handler_list, list) { |
119 | 0 | if (name) { |
120 | 0 | bool found = false; |
121 | |
|
122 | 0 | if (tmp->name && !strcmp(name, tmp->name)) |
123 | 0 | found = true; |
124 | 0 | if (tmp->dev && !strcmp(name, dev_name(tmp->dev))) |
125 | 0 | found = true; |
126 | 0 | if (!found) |
127 | 0 | continue; |
128 | 0 | } |
129 | | |
130 | 0 | if (flags && (tmp->flags & flags) != flags) |
131 | 0 | continue; |
132 | 0 | if (tmp->priority > priority) { |
133 | 0 | priority = tmp->priority; |
134 | 0 | rst = tmp; |
135 | 0 | } |
136 | 0 | } |
137 | |
|
138 | 0 | return rst; |
139 | 0 | } |
140 | | |
141 | | /** |
142 | | * rt_restart_machine() - reset the machine from a runtime service |
143 | | */ |
144 | | void __noreturn __efi_runtime rt_restart_machine(unsigned long flags) |
145 | 0 | { |
146 | 0 | if ((flags & RESTART_WARM) && rt_restart_warm) |
147 | 0 | rt_restart_warm(flags); |
148 | 0 | if (rt_restart) |
149 | 0 | rt_restart(flags); |
150 | |
|
151 | 0 | __hang(); |
152 | 0 | } |
153 | | |
154 | | /** |
155 | | * restart_machine() - reset the whole system |
156 | | */ |
157 | | void __noreturn restart_machine(unsigned long flags) |
158 | 0 | { |
159 | 0 | struct restart_handler *rst; |
160 | |
|
161 | 0 | rst = restart_handler_get_by_name(NULL, 0); |
162 | 0 | if (rst) { |
163 | 0 | pr_debug("%s: using restart handler %s\n", __func__, rst->name); |
164 | 0 | console_flush(); |
165 | 0 | rst->restart(rst, flags); |
166 | 0 | } |
167 | |
|
168 | 0 | hang(); |
169 | 0 | } |
170 | | |
171 | | /* |
172 | | * restart_handlers_print - print informations about all restart handlers |
173 | | */ |
174 | | void restart_handlers_print(void) |
175 | 0 | { |
176 | 0 | struct restart_handler *tmp; |
177 | |
|
178 | 0 | list_for_each_entry(tmp, &restart_handler_list, list) { |
179 | 0 | printf("%-20s %-20s %6d ", |
180 | 0 | tmp->name, tmp->dev ? dev_name(tmp->dev) : "", tmp->priority); |
181 | 0 | if (tmp->flags & RESTART_WARM) |
182 | 0 | putchar('W'); |
183 | 0 | putchar('\n'); |
184 | 0 | } |
185 | |
|
186 | 0 | printf("\nW: Warm restart capable\n"); |
187 | 0 | } |