Merge tag 'arm-dt-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / firmware / arm_scmi / scmi_power_control.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * SCMI Generic SystemPower Control driver.
4  *
5  * Copyright (C) 2020-2022 ARM Ltd.
6  */
7 /*
8  * In order to handle platform originated SCMI SystemPower requests (like
9  * shutdowns or cold/warm resets) we register an SCMI Notification notifier
10  * block to react when such SCMI SystemPower events are emitted by platform.
11  *
12  * Once such a notification is received we act accordingly to perform the
13  * required system transition depending on the kind of request.
14  *
15  * Graceful requests are routed to userspace through the same API methods
16  * (orderly_poweroff/reboot()) used by ACPI when handling ACPI Shutdown bus
17  * events.
18  *
19  * Direct forceful requests are not supported since are not meant to be sent
20  * by the SCMI platform to an OSPM like Linux.
21  *
22  * Additionally, graceful request notifications can carry an optional timeout
23  * field stating the maximum amount of time allowed by the platform for
24  * completion after which they are converted to forceful ones: the assumption
25  * here is that even graceful requests can be upper-bound by a maximum final
26  * timeout strictly enforced by the platform itself which can ultimately cut
27  * the power off at will anytime; in order to avoid such extreme scenario, we
28  * track progress of graceful requests through the means of a reboot notifier
29  * converting timed-out graceful requests to forceful ones, so at least we
30  * try to perform a clean sync and shutdown/restart before the power is cut.
31  *
32  * Given the peculiar nature of SCMI SystemPower protocol, that is being in
33  * charge of triggering system wide shutdown/reboot events, there should be
34  * only one SCMI platform actively emitting SystemPower events.
35  * For this reason the SCMI core takes care to enforce the creation of one
36  * single unique device associated to the SCMI System Power protocol; no matter
37  * how many SCMI platforms are defined on the system, only one can be designated
38  * to support System Power: as a consequence this driver will never be probed
39  * more than once.
40  *
41  * For similar reasons as soon as the first valid SystemPower is received by
42  * this driver and the shutdown/reboot is started, any further notification
43  * possibly emitted by the platform will be ignored.
44  */
45
46 #include <linux/math.h>
47 #include <linux/module.h>
48 #include <linux/mutex.h>
49 #include <linux/printk.h>
50 #include <linux/reboot.h>
51 #include <linux/scmi_protocol.h>
52 #include <linux/slab.h>
53 #include <linux/time64.h>
54 #include <linux/timer.h>
55 #include <linux/types.h>
56 #include <linux/workqueue.h>
57
58 #ifndef MODULE
59 #include <linux/fs.h>
60 #endif
61
62 enum scmi_syspower_state {
63         SCMI_SYSPOWER_IDLE,
64         SCMI_SYSPOWER_IN_PROGRESS,
65         SCMI_SYSPOWER_REBOOTING
66 };
67
68 /**
69  * struct scmi_syspower_conf  -  Common configuration
70  *
71  * @dev: A reference device
72  * @state: Current SystemPower state
73  * @state_mtx: @state related mutex
74  * @required_transition: The requested transition as decribed in the received
75  *                       SCMI SystemPower notification
76  * @userspace_nb: The notifier_block registered against the SCMI SystemPower
77  *                notification to start the needed userspace interactions.
78  * @reboot_nb: A notifier_block optionally used to track reboot progress
79  * @forceful_work: A worker used to trigger a forceful transition once a
80  *                 graceful has timed out.
81  */
82 struct scmi_syspower_conf {
83         struct device *dev;
84         enum scmi_syspower_state state;
85         /* Protect access to state */
86         struct mutex state_mtx;
87         enum scmi_system_events required_transition;
88
89         struct notifier_block userspace_nb;
90         struct notifier_block reboot_nb;
91
92         struct delayed_work forceful_work;
93 };
94
95 #define userspace_nb_to_sconf(x)        \
96         container_of(x, struct scmi_syspower_conf, userspace_nb)
97
98 #define reboot_nb_to_sconf(x)           \
99         container_of(x, struct scmi_syspower_conf, reboot_nb)
100
101 #define dwork_to_sconf(x)               \
102         container_of(x, struct scmi_syspower_conf, forceful_work)
103
104 /**
105  * scmi_reboot_notifier  - A reboot notifier to catch an ongoing successful
106  * system transition
107  * @nb: Reference to the related notifier block
108  * @reason: The reason for the ongoing reboot
109  * @__unused: The cmd being executed on a restart request (unused)
110  *
111  * When an ongoing system transition is detected, compatible with the one
112  * requested by SCMI, cancel the delayed work.
113  *
114  * Return: NOTIFY_OK in any case
115  */
116 static int scmi_reboot_notifier(struct notifier_block *nb,
117                                 unsigned long reason, void *__unused)
118 {
119         struct scmi_syspower_conf *sc = reboot_nb_to_sconf(nb);
120
121         mutex_lock(&sc->state_mtx);
122         switch (reason) {
123         case SYS_HALT:
124         case SYS_POWER_OFF:
125                 if (sc->required_transition == SCMI_SYSTEM_SHUTDOWN)
126                         sc->state = SCMI_SYSPOWER_REBOOTING;
127                 break;
128         case SYS_RESTART:
129                 if (sc->required_transition == SCMI_SYSTEM_COLDRESET ||
130                     sc->required_transition == SCMI_SYSTEM_WARMRESET)
131                         sc->state = SCMI_SYSPOWER_REBOOTING;
132                 break;
133         default:
134                 break;
135         }
136
137         if (sc->state == SCMI_SYSPOWER_REBOOTING) {
138                 dev_dbg(sc->dev, "Reboot in progress...cancel delayed work.\n");
139                 cancel_delayed_work_sync(&sc->forceful_work);
140         }
141         mutex_unlock(&sc->state_mtx);
142
143         return NOTIFY_OK;
144 }
145
146 /**
147  * scmi_request_forceful_transition  - Request forceful SystemPower transition
148  * @sc: A reference to the configuration data
149  *
150  * Initiates the required SystemPower transition without involving userspace:
151  * just trigger the action at the kernel level after issuing an emergency
152  * sync. (if possible at all)
153  */
154 static inline void
155 scmi_request_forceful_transition(struct scmi_syspower_conf *sc)
156 {
157         dev_dbg(sc->dev, "Serving forceful request:%d\n",
158                 sc->required_transition);
159
160 #ifndef MODULE
161         emergency_sync();
162 #endif
163         switch (sc->required_transition) {
164         case SCMI_SYSTEM_SHUTDOWN:
165                 kernel_power_off();
166                 break;
167         case SCMI_SYSTEM_COLDRESET:
168         case SCMI_SYSTEM_WARMRESET:
169                 kernel_restart(NULL);
170                 break;
171         default:
172                 break;
173         }
174 }
175
176 static void scmi_forceful_work_func(struct work_struct *work)
177 {
178         struct scmi_syspower_conf *sc;
179         struct delayed_work *dwork;
180
181         if (system_state > SYSTEM_RUNNING)
182                 return;
183
184         dwork = to_delayed_work(work);
185         sc = dwork_to_sconf(dwork);
186
187         dev_dbg(sc->dev, "Graceful request timed out...forcing !\n");
188         mutex_lock(&sc->state_mtx);
189         /* avoid deadlock by unregistering reboot notifier first */
190         unregister_reboot_notifier(&sc->reboot_nb);
191         if (sc->state == SCMI_SYSPOWER_IN_PROGRESS)
192                 scmi_request_forceful_transition(sc);
193         mutex_unlock(&sc->state_mtx);
194 }
195
196 /**
197  * scmi_request_graceful_transition  - Request graceful SystemPower transition
198  * @sc: A reference to the configuration data
199  * @timeout_ms: The desired timeout to wait for the shutdown to complete before
200  *              system is forcibly shutdown.
201  *
202  * Initiates the required SystemPower transition, requesting userspace
203  * co-operation: it uses the same orderly_ methods used by ACPI Shutdown event
204  * processing.
205  *
206  * Takes care also to register a reboot notifier and to schedule a delayed work
207  * in order to detect if userspace actions are taking too long and in such a
208  * case to trigger a forceful transition.
209  */
210 static void scmi_request_graceful_transition(struct scmi_syspower_conf *sc,
211                                              unsigned int timeout_ms)
212 {
213         unsigned int adj_timeout_ms = 0;
214
215         if (timeout_ms) {
216                 int ret;
217
218                 sc->reboot_nb.notifier_call = &scmi_reboot_notifier;
219                 ret = register_reboot_notifier(&sc->reboot_nb);
220                 if (!ret) {
221                         /* Wait only up to 75% of the advertised timeout */
222                         adj_timeout_ms = mult_frac(timeout_ms, 3, 4);
223                         INIT_DELAYED_WORK(&sc->forceful_work,
224                                           scmi_forceful_work_func);
225                         schedule_delayed_work(&sc->forceful_work,
226                                               msecs_to_jiffies(adj_timeout_ms));
227                 } else {
228                         /* Carry on best effort even without a reboot notifier */
229                         dev_warn(sc->dev,
230                                  "Cannot register reboot notifier !\n");
231                 }
232         }
233
234         dev_dbg(sc->dev,
235                 "Serving graceful req:%d (timeout_ms:%u  adj_timeout_ms:%u)\n",
236                 sc->required_transition, timeout_ms, adj_timeout_ms);
237
238         switch (sc->required_transition) {
239         case SCMI_SYSTEM_SHUTDOWN:
240                 /*
241                  * When triggered early at boot-time the 'orderly' call will
242                  * partially fail due to the lack of userspace itself, but
243                  * the force=true argument will start anyway a successful
244                  * forced shutdown.
245                  */
246                 orderly_poweroff(true);
247                 break;
248         case SCMI_SYSTEM_COLDRESET:
249         case SCMI_SYSTEM_WARMRESET:
250                 orderly_reboot();
251                 break;
252         default:
253                 break;
254         }
255 }
256
257 /**
258  * scmi_userspace_notifier  - Notifier callback to act on SystemPower
259  * Notifications
260  * @nb: Reference to the related notifier block
261  * @event: The SystemPower notification event id
262  * @data: The SystemPower event report
263  *
264  * This callback is in charge of decoding the received SystemPower report
265  * and act accordingly triggering a graceful or forceful system transition.
266  *
267  * Note that once a valid SCMI SystemPower event starts being served, any
268  * other following SystemPower notification received from the same SCMI
269  * instance (handle) will be ignored.
270  *
271  * Return: NOTIFY_OK once a valid SystemPower event has been successfully
272  * processed.
273  */
274 static int scmi_userspace_notifier(struct notifier_block *nb,
275                                    unsigned long event, void *data)
276 {
277         struct scmi_system_power_state_notifier_report *er = data;
278         struct scmi_syspower_conf *sc = userspace_nb_to_sconf(nb);
279
280         if (er->system_state >= SCMI_SYSTEM_POWERUP) {
281                 dev_err(sc->dev, "Ignoring unsupported system_state: 0x%X\n",
282                         er->system_state);
283                 return NOTIFY_DONE;
284         }
285
286         if (!SCMI_SYSPOWER_IS_REQUEST_GRACEFUL(er->flags)) {
287                 dev_err(sc->dev, "Ignoring forceful notification.\n");
288                 return NOTIFY_DONE;
289         }
290
291         /*
292          * Bail out if system is already shutting down or an SCMI SystemPower
293          * requested is already being served.
294          */
295         if (system_state > SYSTEM_RUNNING)
296                 return NOTIFY_DONE;
297         mutex_lock(&sc->state_mtx);
298         if (sc->state != SCMI_SYSPOWER_IDLE) {
299                 dev_dbg(sc->dev,
300                         "Transition already in progress...ignore.\n");
301                 mutex_unlock(&sc->state_mtx);
302                 return NOTIFY_DONE;
303         }
304         sc->state = SCMI_SYSPOWER_IN_PROGRESS;
305         mutex_unlock(&sc->state_mtx);
306
307         sc->required_transition = er->system_state;
308
309         /* Leaving a trace in logs of who triggered the shutdown/reboot. */
310         dev_info(sc->dev, "Serving shutdown/reboot request: %d\n",
311                  sc->required_transition);
312
313         scmi_request_graceful_transition(sc, er->timeout);
314
315         return NOTIFY_OK;
316 }
317
318 static int scmi_syspower_probe(struct scmi_device *sdev)
319 {
320         int ret;
321         struct scmi_syspower_conf *sc;
322         struct scmi_handle *handle = sdev->handle;
323
324         if (!handle)
325                 return -ENODEV;
326
327         ret = handle->devm_protocol_acquire(sdev, SCMI_PROTOCOL_SYSTEM);
328         if (ret)
329                 return ret;
330
331         sc = devm_kzalloc(&sdev->dev, sizeof(*sc), GFP_KERNEL);
332         if (!sc)
333                 return -ENOMEM;
334
335         sc->state = SCMI_SYSPOWER_IDLE;
336         mutex_init(&sc->state_mtx);
337         sc->required_transition = SCMI_SYSTEM_MAX;
338         sc->userspace_nb.notifier_call = &scmi_userspace_notifier;
339         sc->dev = &sdev->dev;
340
341         return handle->notify_ops->devm_event_notifier_register(sdev,
342                                                            SCMI_PROTOCOL_SYSTEM,
343                                          SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
344                                                        NULL, &sc->userspace_nb);
345 }
346
347 static const struct scmi_device_id scmi_id_table[] = {
348         { SCMI_PROTOCOL_SYSTEM, "syspower" },
349         { },
350 };
351 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
352
353 static struct scmi_driver scmi_system_power_driver = {
354         .name = "scmi-system-power",
355         .probe = scmi_syspower_probe,
356         .id_table = scmi_id_table,
357 };
358 module_scmi_driver(scmi_system_power_driver);
359
360 MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
361 MODULE_DESCRIPTION("ARM SCMI SystemPower Control driver");
362 MODULE_LICENSE("GPL");