firmware: arm_sdei: Remove while loop in sdei_event_unregister()
[linux-block.git] / drivers / firmware / arm_sdei.c
CommitLineData
ad6eb31e
JM
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2017 Arm Ltd.
3#define pr_fmt(fmt) "sdei: " fmt
4
f96935d3 5#include <acpi/ghes.h>
ad6eb31e
JM
6#include <linux/acpi.h>
7#include <linux/arm_sdei.h>
8#include <linux/arm-smccc.h>
f92b5462 9#include <linux/atomic.h>
ad6eb31e
JM
10#include <linux/bitops.h>
11#include <linux/compiler.h>
da351827 12#include <linux/cpuhotplug.h>
f92b5462 13#include <linux/cpu.h>
da351827 14#include <linux/cpu_pm.h>
ad6eb31e
JM
15#include <linux/errno.h>
16#include <linux/hardirq.h>
17#include <linux/kernel.h>
18#include <linux/kprobes.h>
19#include <linux/kvm_host.h>
20#include <linux/list.h>
21#include <linux/mutex.h>
da351827 22#include <linux/notifier.h>
ad6eb31e
JM
23#include <linux/of.h>
24#include <linux/of_platform.h>
25#include <linux/percpu.h>
26#include <linux/platform_device.h>
da351827 27#include <linux/pm.h>
ad6eb31e
JM
28#include <linux/ptrace.h>
29#include <linux/preempt.h>
da351827 30#include <linux/reboot.h>
ad6eb31e
JM
31#include <linux/slab.h>
32#include <linux/smp.h>
33#include <linux/spinlock.h>
34#include <linux/uaccess.h>
35
36/*
37 * The call to use to reach the firmware.
38 */
39static asmlinkage void (*sdei_firmware_call)(unsigned long function_id,
40 unsigned long arg0, unsigned long arg1,
41 unsigned long arg2, unsigned long arg3,
42 unsigned long arg4, struct arm_smccc_res *res);
43
44/* entry point from firmware to arch asm code */
45static unsigned long sdei_entry_point;
46
47struct sdei_event {
da351827 48 /* These three are protected by the sdei_list_lock */
ad6eb31e 49 struct list_head list;
da351827
JM
50 bool reregister;
51 bool reenable;
52
ad6eb31e
JM
53 u32 event_num;
54 u8 type;
55 u8 priority;
56
57 /* This pointer is handed to firmware as the event argument. */
f92b5462
JM
58 union {
59 /* Shared events */
60 struct sdei_registered_event *registered;
61
62 /* CPU private events */
63 struct sdei_registered_event __percpu *private_registered;
64 };
ad6eb31e
JM
65};
66
67/* Take the mutex for any API call or modification. Take the mutex first. */
68static DEFINE_MUTEX(sdei_events_lock);
69
70/* and then hold this when modifying the list */
71static DEFINE_SPINLOCK(sdei_list_lock);
72static LIST_HEAD(sdei_list);
73
f92b5462
JM
74/* Private events are registered/enabled via IPI passing one of these */
75struct sdei_crosscall_args {
76 struct sdei_event *event;
77 atomic_t errors;
78 int first_error;
79};
80
81#define CROSSCALL_INIT(arg, event) (arg.event = event, \
82 arg.first_error = 0, \
83 atomic_set(&arg.errors, 0))
84
85static inline int sdei_do_cross_call(void *fn, struct sdei_event * event)
86{
87 struct sdei_crosscall_args arg;
88
89 CROSSCALL_INIT(arg, event);
90 on_each_cpu(fn, &arg, true);
91
92 return arg.first_error;
93}
94
95static inline void
96sdei_cross_call_return(struct sdei_crosscall_args *arg, int err)
97{
98 if (err && (atomic_inc_return(&arg->errors) == 1))
99 arg->first_error = err;
100}
101
ad6eb31e
JM
102static int sdei_to_linux_errno(unsigned long sdei_err)
103{
104 switch (sdei_err) {
105 case SDEI_NOT_SUPPORTED:
106 return -EOPNOTSUPP;
107 case SDEI_INVALID_PARAMETERS:
108 return -EINVAL;
109 case SDEI_DENIED:
110 return -EPERM;
111 case SDEI_PENDING:
112 return -EINPROGRESS;
113 case SDEI_OUT_OF_RESOURCE:
114 return -ENOMEM;
115 }
116
5735f515 117 return 0;
ad6eb31e
JM
118}
119
120static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
121 unsigned long arg1, unsigned long arg2,
122 unsigned long arg3, unsigned long arg4,
123 u64 *result)
124{
5735f515 125 int err;
ad6eb31e
JM
126 struct arm_smccc_res res;
127
128 if (sdei_firmware_call) {
129 sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4,
130 &res);
5735f515 131 err = sdei_to_linux_errno(res.a0);
ad6eb31e
JM
132 } else {
133 /*
134 * !sdei_firmware_call means we failed to probe or called
135 * sdei_mark_interface_broken(). -EIO is not an error returned
136 * by sdei_to_linux_errno() and is used to suppress messages
137 * from this driver.
138 */
139 err = -EIO;
140 res.a0 = SDEI_NOT_SUPPORTED;
141 }
142
143 if (result)
144 *result = res.a0;
145
146 return err;
147}
2f1d4e24 148NOKPROBE_SYMBOL(invoke_sdei_fn);
ad6eb31e
JM
149
150static struct sdei_event *sdei_event_find(u32 event_num)
151{
152 struct sdei_event *e, *found = NULL;
153
154 lockdep_assert_held(&sdei_events_lock);
155
156 spin_lock(&sdei_list_lock);
157 list_for_each_entry(e, &sdei_list, list) {
158 if (e->event_num == event_num) {
159 found = e;
160 break;
161 }
162 }
163 spin_unlock(&sdei_list_lock);
164
165 return found;
166}
167
168int sdei_api_event_context(u32 query, u64 *result)
169{
170 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, query, 0, 0, 0, 0,
171 result);
172}
173NOKPROBE_SYMBOL(sdei_api_event_context);
174
175static int sdei_api_event_get_info(u32 event, u32 info, u64 *result)
176{
177 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0,
178 0, 0, result);
179}
180
181static struct sdei_event *sdei_event_create(u32 event_num,
182 sdei_event_callback *cb,
183 void *cb_arg)
184{
185 int err;
186 u64 result;
187 struct sdei_event *event;
188 struct sdei_registered_event *reg;
189
190 lockdep_assert_held(&sdei_events_lock);
191
192 event = kzalloc(sizeof(*event), GFP_KERNEL);
11988424
GS
193 if (!event) {
194 err = -ENOMEM;
195 goto fail;
196 }
ad6eb31e
JM
197
198 INIT_LIST_HEAD(&event->list);
199 event->event_num = event_num;
200
201 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
202 &result);
11988424
GS
203 if (err)
204 goto fail;
ad6eb31e
JM
205 event->priority = result;
206
207 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE,
208 &result);
11988424
GS
209 if (err)
210 goto fail;
ad6eb31e
JM
211 event->type = result;
212
213 if (event->type == SDEI_EVENT_TYPE_SHARED) {
214 reg = kzalloc(sizeof(*reg), GFP_KERNEL);
215 if (!reg) {
11988424
GS
216 err = -ENOMEM;
217 goto fail;
ad6eb31e
JM
218 }
219
663c0e89 220 reg->event_num = event->event_num;
ad6eb31e
JM
221 reg->priority = event->priority;
222
223 reg->callback = cb;
224 reg->callback_arg = cb_arg;
225 event->registered = reg;
f92b5462
JM
226 } else {
227 int cpu;
228 struct sdei_registered_event __percpu *regs;
229
230 regs = alloc_percpu(struct sdei_registered_event);
231 if (!regs) {
11988424
GS
232 err = -ENOMEM;
233 goto fail;
f92b5462
JM
234 }
235
236 for_each_possible_cpu(cpu) {
237 reg = per_cpu_ptr(regs, cpu);
238
239 reg->event_num = event->event_num;
240 reg->priority = event->priority;
241 reg->callback = cb;
242 reg->callback_arg = cb_arg;
243 }
244
245 event->private_registered = regs;
ad6eb31e
JM
246 }
247
f7d5ef0c
LZ
248 spin_lock(&sdei_list_lock);
249 list_add(&event->list, &sdei_list);
250 spin_unlock(&sdei_list_lock);
ad6eb31e
JM
251
252 return event;
11988424
GS
253
254fail:
255 kfree(event);
256 return ERR_PTR(err);
ad6eb31e
JM
257}
258
c66d52b1 259static void sdei_event_destroy_llocked(struct sdei_event *event)
ad6eb31e
JM
260{
261 lockdep_assert_held(&sdei_events_lock);
c66d52b1 262 lockdep_assert_held(&sdei_list_lock);
ad6eb31e 263
ad6eb31e 264 list_del(&event->list);
ad6eb31e
JM
265
266 if (event->type == SDEI_EVENT_TYPE_SHARED)
267 kfree(event->registered);
f92b5462
JM
268 else
269 free_percpu(event->private_registered);
ad6eb31e
JM
270
271 kfree(event);
272}
273
c66d52b1
LZ
274static void sdei_event_destroy(struct sdei_event *event)
275{
276 spin_lock(&sdei_list_lock);
277 sdei_event_destroy_llocked(event);
278 spin_unlock(&sdei_list_lock);
279}
280
ad6eb31e
JM
281static int sdei_api_get_version(u64 *version)
282{
283 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version);
284}
285
286int sdei_mask_local_cpu(void)
287{
288 int err;
289
290 WARN_ON_ONCE(preemptible());
291
292 err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL);
293 if (err && err != -EIO) {
294 pr_warn_once("failed to mask CPU[%u]: %d\n",
295 smp_processor_id(), err);
296 return err;
297 }
298
299 return 0;
300}
301
302static void _ipi_mask_cpu(void *ignored)
303{
304 sdei_mask_local_cpu();
305}
306
307int sdei_unmask_local_cpu(void)
308{
309 int err;
310
311 WARN_ON_ONCE(preemptible());
312
313 err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL);
314 if (err && err != -EIO) {
315 pr_warn_once("failed to unmask CPU[%u]: %d\n",
316 smp_processor_id(), err);
317 return err;
318 }
319
320 return 0;
321}
322
323static void _ipi_unmask_cpu(void *ignored)
324{
325 sdei_unmask_local_cpu();
326}
327
328static void _ipi_private_reset(void *ignored)
329{
330 int err;
331
332 err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0,
333 NULL);
334 if (err && err != -EIO)
335 pr_warn_once("failed to reset CPU[%u]: %d\n",
336 smp_processor_id(), err);
337}
338
339static int sdei_api_shared_reset(void)
340{
341 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_SHARED_RESET, 0, 0, 0, 0, 0,
342 NULL);
343}
344
345static void sdei_mark_interface_broken(void)
346{
347 pr_err("disabling SDEI firmware interface\n");
348 on_each_cpu(&_ipi_mask_cpu, NULL, true);
349 sdei_firmware_call = NULL;
350}
351
352static int sdei_platform_reset(void)
353{
354 int err;
355
356 on_each_cpu(&_ipi_private_reset, NULL, true);
357 err = sdei_api_shared_reset();
358 if (err) {
359 pr_err("Failed to reset platform: %d\n", err);
360 sdei_mark_interface_broken();
361 }
362
363 return err;
364}
365
366static int sdei_api_event_enable(u32 event_num)
367{
368 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ENABLE, event_num, 0, 0, 0,
369 0, NULL);
370}
371
f92b5462
JM
372/* Called directly by the hotplug callbacks */
373static void _local_event_enable(void *data)
374{
375 int err;
376 struct sdei_crosscall_args *arg = data;
377
378 WARN_ON_ONCE(preemptible());
379
380 err = sdei_api_event_enable(arg->event->event_num);
381
382 sdei_cross_call_return(arg, err);
383}
384
ad6eb31e
JM
385int sdei_event_enable(u32 event_num)
386{
387 int err = -EINVAL;
388 struct sdei_event *event;
389
390 mutex_lock(&sdei_events_lock);
391 event = sdei_event_find(event_num);
392 if (!event) {
393 mutex_unlock(&sdei_events_lock);
394 return -ENOENT;
395 }
396
da351827 397
54f529a6 398 cpus_read_lock();
ad6eb31e
JM
399 if (event->type == SDEI_EVENT_TYPE_SHARED)
400 err = sdei_api_event_enable(event->event_num);
f92b5462
JM
401 else
402 err = sdei_do_cross_call(_local_event_enable, event);
54f529a6
JM
403
404 if (!err) {
405 spin_lock(&sdei_list_lock);
406 event->reenable = true;
407 spin_unlock(&sdei_list_lock);
408 }
409 cpus_read_unlock();
ad6eb31e
JM
410 mutex_unlock(&sdei_events_lock);
411
412 return err;
413}
ad6eb31e
JM
414
415static int sdei_api_event_disable(u32 event_num)
416{
417 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_DISABLE, event_num, 0, 0,
418 0, 0, NULL);
419}
420
f92b5462
JM
421static void _ipi_event_disable(void *data)
422{
423 int err;
424 struct sdei_crosscall_args *arg = data;
425
426 err = sdei_api_event_disable(arg->event->event_num);
427
428 sdei_cross_call_return(arg, err);
429}
430
ad6eb31e
JM
431int sdei_event_disable(u32 event_num)
432{
433 int err = -EINVAL;
434 struct sdei_event *event;
435
436 mutex_lock(&sdei_events_lock);
437 event = sdei_event_find(event_num);
438 if (!event) {
439 mutex_unlock(&sdei_events_lock);
440 return -ENOENT;
441 }
442
da351827
JM
443 spin_lock(&sdei_list_lock);
444 event->reenable = false;
445 spin_unlock(&sdei_list_lock);
446
ad6eb31e
JM
447 if (event->type == SDEI_EVENT_TYPE_SHARED)
448 err = sdei_api_event_disable(event->event_num);
f92b5462
JM
449 else
450 err = sdei_do_cross_call(_ipi_event_disable, event);
ad6eb31e
JM
451 mutex_unlock(&sdei_events_lock);
452
453 return err;
454}
ad6eb31e
JM
455
456static int sdei_api_event_unregister(u32 event_num)
457{
458 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_UNREGISTER, event_num, 0,
459 0, 0, 0, NULL);
460}
461
f92b5462
JM
462/* Called directly by the hotplug callbacks */
463static void _local_event_unregister(void *data)
464{
465 int err;
466 struct sdei_crosscall_args *arg = data;
467
468 WARN_ON_ONCE(preemptible());
469
470 err = sdei_api_event_unregister(arg->event->event_num);
471
472 sdei_cross_call_return(arg, err);
473}
474
ad6eb31e
JM
475static int _sdei_event_unregister(struct sdei_event *event)
476{
477 lockdep_assert_held(&sdei_events_lock);
478
479 if (event->type == SDEI_EVENT_TYPE_SHARED)
480 return sdei_api_event_unregister(event->event_num);
481
f92b5462 482 return sdei_do_cross_call(_local_event_unregister, event);
ad6eb31e
JM
483}
484
485int sdei_event_unregister(u32 event_num)
486{
487 int err;
488 struct sdei_event *event;
489
490 WARN_ON(in_nmi());
491
492 mutex_lock(&sdei_events_lock);
493 event = sdei_event_find(event_num);
b06146b6
GS
494 if (!event) {
495 pr_warn("Event %u not registered\n", event_num);
496 err = -ENOENT;
497 goto unlock;
498 }
ad6eb31e 499
b06146b6
GS
500 spin_lock(&sdei_list_lock);
501 event->reregister = false;
502 event->reenable = false;
503 spin_unlock(&sdei_list_lock);
6ded0b61 504
b06146b6
GS
505 err = _sdei_event_unregister(event);
506 if (err)
507 goto unlock;
ad6eb31e 508
b06146b6
GS
509 sdei_event_destroy(event);
510unlock:
ad6eb31e
JM
511 mutex_unlock(&sdei_events_lock);
512
513 return err;
514}
ad6eb31e 515
da351827
JM
516/*
517 * unregister events, but don't destroy them as they are re-registered by
518 * sdei_reregister_shared().
519 */
520static int sdei_unregister_shared(void)
521{
522 int err = 0;
523 struct sdei_event *event;
524
525 mutex_lock(&sdei_events_lock);
526 spin_lock(&sdei_list_lock);
527 list_for_each_entry(event, &sdei_list, list) {
528 if (event->type != SDEI_EVENT_TYPE_SHARED)
529 continue;
530
531 err = _sdei_event_unregister(event);
532 if (err)
533 break;
534 }
535 spin_unlock(&sdei_list_lock);
536 mutex_unlock(&sdei_events_lock);
537
538 return err;
539}
540
ad6eb31e
JM
541static int sdei_api_event_register(u32 event_num, unsigned long entry_point,
542 void *arg, u64 flags, u64 affinity)
543{
544 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_REGISTER, event_num,
545 (unsigned long)entry_point, (unsigned long)arg,
546 flags, affinity, NULL);
547}
548
f92b5462
JM
549/* Called directly by the hotplug callbacks */
550static void _local_event_register(void *data)
551{
552 int err;
553 struct sdei_registered_event *reg;
554 struct sdei_crosscall_args *arg = data;
555
556 WARN_ON(preemptible());
557
558 reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id());
559 err = sdei_api_event_register(arg->event->event_num, sdei_entry_point,
560 reg, 0, 0);
561
562 sdei_cross_call_return(arg, err);
563}
564
ad6eb31e
JM
565static int _sdei_event_register(struct sdei_event *event)
566{
f92b5462
JM
567 int err;
568
ad6eb31e
JM
569 lockdep_assert_held(&sdei_events_lock);
570
571 if (event->type == SDEI_EVENT_TYPE_SHARED)
572 return sdei_api_event_register(event->event_num,
573 sdei_entry_point,
574 event->registered,
575 SDEI_EVENT_REGISTER_RM_ANY, 0);
576
f92b5462 577 err = sdei_do_cross_call(_local_event_register, event);
6ded0b61 578 if (err)
f92b5462 579 sdei_do_cross_call(_local_event_unregister, event);
f92b5462
JM
580
581 return err;
ad6eb31e
JM
582}
583
584int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
585{
586 int err;
587 struct sdei_event *event;
588
589 WARN_ON(in_nmi());
590
591 mutex_lock(&sdei_events_lock);
1bbc7551
GS
592 if (sdei_event_find(event_num)) {
593 pr_warn("Event %u already registered\n", event_num);
594 err = -EBUSY;
595 goto unlock;
596 }
ad6eb31e 597
1bbc7551
GS
598 event = sdei_event_create(event_num, cb, arg);
599 if (IS_ERR(event)) {
600 err = PTR_ERR(event);
601 pr_warn("Failed to create event %u: %d\n", event_num, err);
602 goto unlock;
603 }
ad6eb31e 604
1bbc7551
GS
605 cpus_read_lock();
606 err = _sdei_event_register(event);
607 if (err) {
608 sdei_event_destroy(event);
609 pr_warn("Failed to register event %u: %d\n", event_num, err);
610 goto cpu_unlock;
611 }
ad6eb31e 612
1bbc7551
GS
613 spin_lock(&sdei_list_lock);
614 event->reregister = true;
615 spin_unlock(&sdei_list_lock);
616cpu_unlock:
617 cpus_read_unlock();
618unlock:
619 mutex_unlock(&sdei_events_lock);
ad6eb31e
JM
620 return err;
621}
ad6eb31e 622
c66d52b1 623static int sdei_reregister_event_llocked(struct sdei_event *event)
da351827
JM
624{
625 int err;
626
627 lockdep_assert_held(&sdei_events_lock);
c66d52b1 628 lockdep_assert_held(&sdei_list_lock);
da351827
JM
629
630 err = _sdei_event_register(event);
631 if (err) {
632 pr_err("Failed to re-register event %u\n", event->event_num);
c66d52b1 633 sdei_event_destroy_llocked(event);
da351827
JM
634 return err;
635 }
636
637 if (event->reenable) {
638 if (event->type == SDEI_EVENT_TYPE_SHARED)
639 err = sdei_api_event_enable(event->event_num);
f92b5462
JM
640 else
641 err = sdei_do_cross_call(_local_event_enable, event);
da351827
JM
642 }
643
644 if (err)
645 pr_err("Failed to re-enable event %u\n", event->event_num);
646
647 return err;
648}
649
650static int sdei_reregister_shared(void)
651{
652 int err = 0;
653 struct sdei_event *event;
654
655 mutex_lock(&sdei_events_lock);
656 spin_lock(&sdei_list_lock);
657 list_for_each_entry(event, &sdei_list, list) {
658 if (event->type != SDEI_EVENT_TYPE_SHARED)
659 continue;
660
661 if (event->reregister) {
c66d52b1 662 err = sdei_reregister_event_llocked(event);
da351827
JM
663 if (err)
664 break;
665 }
666 }
667 spin_unlock(&sdei_list_lock);
668 mutex_unlock(&sdei_events_lock);
669
670 return err;
671}
672
f92b5462
JM
673static int sdei_cpuhp_down(unsigned int cpu)
674{
675 struct sdei_event *event;
676 struct sdei_crosscall_args arg;
677
678 /* un-register private events */
679 spin_lock(&sdei_list_lock);
680 list_for_each_entry(event, &sdei_list, list) {
681 if (event->type == SDEI_EVENT_TYPE_SHARED)
682 continue;
683
684 CROSSCALL_INIT(arg, event);
685 /* call the cross-call function locally... */
686 _local_event_unregister(&arg);
687 if (arg.first_error)
688 pr_err("Failed to unregister event %u: %d\n",
689 event->event_num, arg.first_error);
690 }
691 spin_unlock(&sdei_list_lock);
692
693 return sdei_mask_local_cpu();
694}
695
696static int sdei_cpuhp_up(unsigned int cpu)
697{
698 struct sdei_event *event;
699 struct sdei_crosscall_args arg;
700
701 /* re-register/enable private events */
702 spin_lock(&sdei_list_lock);
703 list_for_each_entry(event, &sdei_list, list) {
704 if (event->type == SDEI_EVENT_TYPE_SHARED)
705 continue;
706
707 if (event->reregister) {
708 CROSSCALL_INIT(arg, event);
709 /* call the cross-call function locally... */
710 _local_event_register(&arg);
711 if (arg.first_error)
712 pr_err("Failed to re-register event %u: %d\n",
713 event->event_num, arg.first_error);
714 }
715
716 if (event->reenable) {
717 CROSSCALL_INIT(arg, event);
718 _local_event_enable(&arg);
719 if (arg.first_error)
720 pr_err("Failed to re-enable event %u: %d\n",
721 event->event_num, arg.first_error);
722 }
723 }
724 spin_unlock(&sdei_list_lock);
725
726 return sdei_unmask_local_cpu();
727}
728
da351827
JM
729/* When entering idle, mask/unmask events for this cpu */
730static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action,
731 void *data)
732{
733 int rv;
734
735 switch (action) {
736 case CPU_PM_ENTER:
737 rv = sdei_mask_local_cpu();
738 break;
739 case CPU_PM_EXIT:
740 case CPU_PM_ENTER_FAILED:
741 rv = sdei_unmask_local_cpu();
742 break;
743 default:
744 return NOTIFY_DONE;
745 }
746
747 if (rv)
748 return notifier_from_errno(rv);
749
750 return NOTIFY_OK;
751}
752
753static struct notifier_block sdei_pm_nb = {
754 .notifier_call = sdei_pm_notifier,
755};
756
757static int sdei_device_suspend(struct device *dev)
758{
759 on_each_cpu(_ipi_mask_cpu, NULL, true);
760
761 return 0;
762}
763
764static int sdei_device_resume(struct device *dev)
765{
766 on_each_cpu(_ipi_unmask_cpu, NULL, true);
767
768 return 0;
769}
770
771/*
772 * We need all events to be reregistered when we resume from hibernate.
773 *
774 * The sequence is freeze->thaw. Reboot. freeze->restore. We unregister
775 * events during freeze, then re-register and re-enable them during thaw
776 * and restore.
777 */
778static int sdei_device_freeze(struct device *dev)
779{
780 int err;
781
f92b5462 782 /* unregister private events */
da351827
JM
783 cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
784
785 err = sdei_unregister_shared();
786 if (err)
787 return err;
788
789 return 0;
790}
791
792static int sdei_device_thaw(struct device *dev)
793{
794 int err;
795
796 /* re-register shared events */
797 err = sdei_reregister_shared();
798 if (err) {
799 pr_warn("Failed to re-register shared events...\n");
800 sdei_mark_interface_broken();
801 return err;
802 }
803
804 err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
805 &sdei_cpuhp_up, &sdei_cpuhp_down);
806 if (err)
807 pr_warn("Failed to re-register CPU hotplug notifier...\n");
808
809 return err;
810}
811
812static int sdei_device_restore(struct device *dev)
813{
814 int err;
815
816 err = sdei_platform_reset();
817 if (err)
818 return err;
819
820 return sdei_device_thaw(dev);
821}
822
823static const struct dev_pm_ops sdei_pm_ops = {
824 .suspend = sdei_device_suspend,
825 .resume = sdei_device_resume,
826 .freeze = sdei_device_freeze,
827 .thaw = sdei_device_thaw,
828 .restore = sdei_device_restore,
829};
830
831/*
832 * Mask all CPUs and unregister all events on panic, reboot or kexec.
833 */
834static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action,
835 void *data)
836{
837 /*
838 * We are going to reset the interface, after this there is no point
839 * doing work when we take CPUs offline.
840 */
841 cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
842
843 sdei_platform_reset();
844
845 return NOTIFY_OK;
846}
847
848static struct notifier_block sdei_reboot_nb = {
849 .notifier_call = sdei_reboot_notifier,
850};
851
ad6eb31e
JM
852static void sdei_smccc_smc(unsigned long function_id,
853 unsigned long arg0, unsigned long arg1,
854 unsigned long arg2, unsigned long arg3,
855 unsigned long arg4, struct arm_smccc_res *res)
856{
857 arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
858}
2f1d4e24 859NOKPROBE_SYMBOL(sdei_smccc_smc);
ad6eb31e
JM
860
861static void sdei_smccc_hvc(unsigned long function_id,
862 unsigned long arg0, unsigned long arg1,
863 unsigned long arg2, unsigned long arg3,
864 unsigned long arg4, struct arm_smccc_res *res)
865{
866 arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
867}
2f1d4e24 868NOKPROBE_SYMBOL(sdei_smccc_hvc);
ad6eb31e 869
f96935d3
JM
870int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
871 sdei_event_callback *critical_cb)
872{
873 int err;
874 u64 result;
875 u32 event_num;
876 sdei_event_callback *cb;
877
878 if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
879 return -EOPNOTSUPP;
880
881 event_num = ghes->generic->notify.vector;
882 if (event_num == 0) {
883 /*
884 * Event 0 is reserved by the specification for
885 * SDEI_EVENT_SIGNAL.
886 */
887 return -EINVAL;
888 }
889
890 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
891 &result);
892 if (err)
893 return err;
894
895 if (result == SDEI_EVENT_PRIORITY_CRITICAL)
896 cb = critical_cb;
897 else
898 cb = normal_cb;
899
900 err = sdei_event_register(event_num, cb, ghes);
901 if (!err)
902 err = sdei_event_enable(event_num);
903
904 return err;
905}
906
907int sdei_unregister_ghes(struct ghes *ghes)
908{
909 int i;
910 int err;
911 u32 event_num = ghes->generic->notify.vector;
912
913 might_sleep();
914
915 if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
916 return -EOPNOTSUPP;
917
918 /*
919 * The event may be running on another CPU. Disable it
920 * to stop new events, then try to unregister a few times.
921 */
922 err = sdei_event_disable(event_num);
923 if (err)
924 return err;
925
926 for (i = 0; i < 3; i++) {
927 err = sdei_event_unregister(event_num);
928 if (err != -EINPROGRESS)
929 break;
930
931 schedule();
932 }
933
934 return err;
935}
936
ad6eb31e
JM
937static int sdei_get_conduit(struct platform_device *pdev)
938{
939 const char *method;
940 struct device_node *np = pdev->dev.of_node;
941
942 sdei_firmware_call = NULL;
943 if (np) {
944 if (of_property_read_string(np, "method", &method)) {
945 pr_warn("missing \"method\" property\n");
e6ea4651 946 return SMCCC_CONDUIT_NONE;
ad6eb31e
JM
947 }
948
949 if (!strcmp("hvc", method)) {
950 sdei_firmware_call = &sdei_smccc_hvc;
e6ea4651 951 return SMCCC_CONDUIT_HVC;
ad6eb31e
JM
952 } else if (!strcmp("smc", method)) {
953 sdei_firmware_call = &sdei_smccc_smc;
e6ea4651 954 return SMCCC_CONDUIT_SMC;
ad6eb31e
JM
955 }
956
957 pr_warn("invalid \"method\" property: %s\n", method);
bc110fd3 958 } else if (!acpi_disabled) {
677a60bd
JM
959 if (acpi_psci_use_hvc()) {
960 sdei_firmware_call = &sdei_smccc_hvc;
e6ea4651 961 return SMCCC_CONDUIT_HVC;
677a60bd
JM
962 } else {
963 sdei_firmware_call = &sdei_smccc_smc;
e6ea4651 964 return SMCCC_CONDUIT_SMC;
677a60bd 965 }
ad6eb31e
JM
966 }
967
e6ea4651 968 return SMCCC_CONDUIT_NONE;
ad6eb31e
JM
969}
970
971static int sdei_probe(struct platform_device *pdev)
972{
973 int err;
974 u64 ver = 0;
975 int conduit;
976
977 conduit = sdei_get_conduit(pdev);
978 if (!sdei_firmware_call)
979 return 0;
980
981 err = sdei_api_get_version(&ver);
ad6eb31e
JM
982 if (err) {
983 pr_err("Failed to get SDEI version: %d\n", err);
984 sdei_mark_interface_broken();
985 return err;
986 }
987
988 pr_info("SDEIv%d.%d (0x%x) detected in firmware.\n",
989 (int)SDEI_VERSION_MAJOR(ver), (int)SDEI_VERSION_MINOR(ver),
990 (int)SDEI_VERSION_VENDOR(ver));
991
992 if (SDEI_VERSION_MAJOR(ver) != 1) {
993 pr_warn("Conflicting SDEI version detected.\n");
994 sdei_mark_interface_broken();
995 return -EINVAL;
996 }
997
998 err = sdei_platform_reset();
999 if (err)
1000 return err;
1001
1002 sdei_entry_point = sdei_arch_get_entry_point(conduit);
1003 if (!sdei_entry_point) {
1004 /* Not supported due to hardware or boot configuration */
1005 sdei_mark_interface_broken();
1006 return 0;
1007 }
1008
da351827
JM
1009 err = cpu_pm_register_notifier(&sdei_pm_nb);
1010 if (err) {
1011 pr_warn("Failed to register CPU PM notifier...\n");
1012 goto error;
1013 }
1014
1015 err = register_reboot_notifier(&sdei_reboot_nb);
1016 if (err) {
1017 pr_warn("Failed to register reboot notifier...\n");
1018 goto remove_cpupm;
1019 }
1020
1021 err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
1022 &sdei_cpuhp_up, &sdei_cpuhp_down);
1023 if (err) {
1024 pr_warn("Failed to register CPU hotplug notifier...\n");
1025 goto remove_reboot;
1026 }
ad6eb31e
JM
1027
1028 return 0;
da351827
JM
1029
1030remove_reboot:
1031 unregister_reboot_notifier(&sdei_reboot_nb);
1032
1033remove_cpupm:
1034 cpu_pm_unregister_notifier(&sdei_pm_nb);
1035
1036error:
1037 sdei_mark_interface_broken();
1038 return err;
ad6eb31e
JM
1039}
1040
1041static const struct of_device_id sdei_of_match[] = {
1042 { .compatible = "arm,sdei-1.0" },
1043 {}
1044};
1045
1046static struct platform_driver sdei_driver = {
1047 .driver = {
1048 .name = "sdei",
da351827 1049 .pm = &sdei_pm_ops,
ad6eb31e
JM
1050 .of_match_table = sdei_of_match,
1051 },
1052 .probe = sdei_probe,
1053};
1054
677a60bd
JM
1055static bool __init sdei_present_acpi(void)
1056{
1057 acpi_status status;
677a60bd
JM
1058 struct acpi_table_header *sdei_table_header;
1059
1060 if (acpi_disabled)
1061 return false;
1062
1063 status = acpi_get_table(ACPI_SIG_SDEI, 0, &sdei_table_header);
1064 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
1065 const char *msg = acpi_format_exception(status);
1066
1067 pr_info("Failed to get ACPI:SDEI table, %s\n", msg);
1068 }
1069 if (ACPI_FAILURE(status))
1070 return false;
1071
70e6352a
HG
1072 acpi_put_table(sdei_table_header);
1073
677a60bd
JM
1074 return true;
1075}
1076
ad6eb31e
JM
1077static int __init sdei_init(void)
1078{
10fd7c42
GS
1079 struct platform_device *pdev;
1080 int ret;
1081
1082 ret = platform_driver_register(&sdei_driver);
1083 if (ret || !sdei_present_acpi())
1084 return ret;
1085
1086 pdev = platform_device_register_simple(sdei_driver.driver.name,
1087 0, NULL, 0);
63627cae
GS
1088 if (IS_ERR(pdev)) {
1089 ret = PTR_ERR(pdev);
1090 platform_driver_unregister(&sdei_driver);
1091 pr_info("Failed to register ACPI:SDEI platform device %d\n",
1092 ret);
1093 }
caf2cd61
SH
1094
1095 return ret;
ad6eb31e
JM
1096}
1097
677a60bd
JM
1098/*
1099 * On an ACPI system SDEI needs to be ready before HEST:GHES tries to register
1100 * its events. ACPI is initialised from a subsys_initcall(), GHES is initialised
1101 * by device_initcall(). We want to be called in the middle.
1102 */
ad6eb31e
JM
1103subsys_initcall_sync(sdei_init);
1104
1105int sdei_event_handler(struct pt_regs *regs,
1106 struct sdei_registered_event *arg)
1107{
1108 int err;
1109 mm_segment_t orig_addr_limit;
1110 u32 event_num = arg->event_num;
1111
472de63b
JM
1112 /*
1113 * Save restore 'fs'.
1114 * The architecture's entry code save/restores 'fs' when taking an
1115 * exception from the kernel. This ensures addr_limit isn't inherited
1116 * if you interrupted something that allowed the uaccess routines to
1117 * access kernel memory.
1118 * Do the same here because this doesn't come via the same entry code.
1119 */
3d13f313 1120 orig_addr_limit = force_uaccess_begin();
ad6eb31e
JM
1121
1122 err = arg->callback(event_num, regs, arg->callback_arg);
1123 if (err)
1124 pr_err_ratelimited("event %u on CPU %u failed with error: %d\n",
1125 event_num, smp_processor_id(), err);
1126
3d13f313 1127 force_uaccess_end(orig_addr_limit);
ad6eb31e
JM
1128
1129 return err;
1130}
1131NOKPROBE_SYMBOL(sdei_event_handler);