0001
0002
0003 #define pr_fmt(fmt) "sdei: " fmt
0004
0005 #include <acpi/ghes.h>
0006 #include <linux/acpi.h>
0007 #include <linux/arm_sdei.h>
0008 #include <linux/arm-smccc.h>
0009 #include <linux/atomic.h>
0010 #include <linux/bitops.h>
0011 #include <linux/compiler.h>
0012 #include <linux/cpuhotplug.h>
0013 #include <linux/cpu.h>
0014 #include <linux/cpu_pm.h>
0015 #include <linux/errno.h>
0016 #include <linux/hardirq.h>
0017 #include <linux/kernel.h>
0018 #include <linux/kprobes.h>
0019 #include <linux/kvm_host.h>
0020 #include <linux/list.h>
0021 #include <linux/mutex.h>
0022 #include <linux/notifier.h>
0023 #include <linux/of.h>
0024 #include <linux/of_platform.h>
0025 #include <linux/percpu.h>
0026 #include <linux/platform_device.h>
0027 #include <linux/pm.h>
0028 #include <linux/ptrace.h>
0029 #include <linux/preempt.h>
0030 #include <linux/reboot.h>
0031 #include <linux/slab.h>
0032 #include <linux/smp.h>
0033 #include <linux/spinlock.h>
0034
0035
0036
0037
0038 static asmlinkage void (*sdei_firmware_call)(unsigned long function_id,
0039 unsigned long arg0, unsigned long arg1,
0040 unsigned long arg2, unsigned long arg3,
0041 unsigned long arg4, struct arm_smccc_res *res);
0042
0043
0044 static unsigned long sdei_entry_point;
0045
0046 struct sdei_event {
0047
0048 struct list_head list;
0049 bool reregister;
0050 bool reenable;
0051
0052 u32 event_num;
0053 u8 type;
0054 u8 priority;
0055
0056
0057 union {
0058
0059 struct sdei_registered_event *registered;
0060
0061
0062 struct sdei_registered_event __percpu *private_registered;
0063 };
0064 };
0065
0066
0067 static DEFINE_MUTEX(sdei_events_lock);
0068
0069
0070 static DEFINE_SPINLOCK(sdei_list_lock);
0071 static LIST_HEAD(sdei_list);
0072
0073
0074 struct sdei_crosscall_args {
0075 struct sdei_event *event;
0076 atomic_t errors;
0077 int first_error;
0078 };
0079
0080 #define CROSSCALL_INIT(arg, event) \
0081 do { \
0082 arg.event = event; \
0083 arg.first_error = 0; \
0084 atomic_set(&arg.errors, 0); \
0085 } while (0)
0086
0087 static inline int sdei_do_local_call(smp_call_func_t fn,
0088 struct sdei_event *event)
0089 {
0090 struct sdei_crosscall_args arg;
0091
0092 CROSSCALL_INIT(arg, event);
0093 fn(&arg);
0094
0095 return arg.first_error;
0096 }
0097
0098 static inline int sdei_do_cross_call(smp_call_func_t fn,
0099 struct sdei_event *event)
0100 {
0101 struct sdei_crosscall_args arg;
0102
0103 CROSSCALL_INIT(arg, event);
0104 on_each_cpu(fn, &arg, true);
0105
0106 return arg.first_error;
0107 }
0108
0109 static inline void
0110 sdei_cross_call_return(struct sdei_crosscall_args *arg, int err)
0111 {
0112 if (err && (atomic_inc_return(&arg->errors) == 1))
0113 arg->first_error = err;
0114 }
0115
0116 static int sdei_to_linux_errno(unsigned long sdei_err)
0117 {
0118 switch (sdei_err) {
0119 case SDEI_NOT_SUPPORTED:
0120 return -EOPNOTSUPP;
0121 case SDEI_INVALID_PARAMETERS:
0122 return -EINVAL;
0123 case SDEI_DENIED:
0124 return -EPERM;
0125 case SDEI_PENDING:
0126 return -EINPROGRESS;
0127 case SDEI_OUT_OF_RESOURCE:
0128 return -ENOMEM;
0129 }
0130
0131 return 0;
0132 }
0133
0134 static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
0135 unsigned long arg1, unsigned long arg2,
0136 unsigned long arg3, unsigned long arg4,
0137 u64 *result)
0138 {
0139 int err;
0140 struct arm_smccc_res res;
0141
0142 if (sdei_firmware_call) {
0143 sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4,
0144 &res);
0145 err = sdei_to_linux_errno(res.a0);
0146 } else {
0147
0148
0149
0150
0151
0152
0153 err = -EIO;
0154 res.a0 = SDEI_NOT_SUPPORTED;
0155 }
0156
0157 if (result)
0158 *result = res.a0;
0159
0160 return err;
0161 }
0162 NOKPROBE_SYMBOL(invoke_sdei_fn);
0163
0164 static struct sdei_event *sdei_event_find(u32 event_num)
0165 {
0166 struct sdei_event *e, *found = NULL;
0167
0168 lockdep_assert_held(&sdei_events_lock);
0169
0170 spin_lock(&sdei_list_lock);
0171 list_for_each_entry(e, &sdei_list, list) {
0172 if (e->event_num == event_num) {
0173 found = e;
0174 break;
0175 }
0176 }
0177 spin_unlock(&sdei_list_lock);
0178
0179 return found;
0180 }
0181
0182 int sdei_api_event_context(u32 query, u64 *result)
0183 {
0184 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, query, 0, 0, 0, 0,
0185 result);
0186 }
0187 NOKPROBE_SYMBOL(sdei_api_event_context);
0188
0189 static int sdei_api_event_get_info(u32 event, u32 info, u64 *result)
0190 {
0191 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0,
0192 0, 0, result);
0193 }
0194
0195 static struct sdei_event *sdei_event_create(u32 event_num,
0196 sdei_event_callback *cb,
0197 void *cb_arg)
0198 {
0199 int err;
0200 u64 result;
0201 struct sdei_event *event;
0202 struct sdei_registered_event *reg;
0203
0204 lockdep_assert_held(&sdei_events_lock);
0205
0206 event = kzalloc(sizeof(*event), GFP_KERNEL);
0207 if (!event) {
0208 err = -ENOMEM;
0209 goto fail;
0210 }
0211
0212 INIT_LIST_HEAD(&event->list);
0213 event->event_num = event_num;
0214
0215 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
0216 &result);
0217 if (err)
0218 goto fail;
0219 event->priority = result;
0220
0221 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE,
0222 &result);
0223 if (err)
0224 goto fail;
0225 event->type = result;
0226
0227 if (event->type == SDEI_EVENT_TYPE_SHARED) {
0228 reg = kzalloc(sizeof(*reg), GFP_KERNEL);
0229 if (!reg) {
0230 err = -ENOMEM;
0231 goto fail;
0232 }
0233
0234 reg->event_num = event->event_num;
0235 reg->priority = event->priority;
0236
0237 reg->callback = cb;
0238 reg->callback_arg = cb_arg;
0239 event->registered = reg;
0240 } else {
0241 int cpu;
0242 struct sdei_registered_event __percpu *regs;
0243
0244 regs = alloc_percpu(struct sdei_registered_event);
0245 if (!regs) {
0246 err = -ENOMEM;
0247 goto fail;
0248 }
0249
0250 for_each_possible_cpu(cpu) {
0251 reg = per_cpu_ptr(regs, cpu);
0252
0253 reg->event_num = event->event_num;
0254 reg->priority = event->priority;
0255 reg->callback = cb;
0256 reg->callback_arg = cb_arg;
0257 }
0258
0259 event->private_registered = regs;
0260 }
0261
0262 spin_lock(&sdei_list_lock);
0263 list_add(&event->list, &sdei_list);
0264 spin_unlock(&sdei_list_lock);
0265
0266 return event;
0267
0268 fail:
0269 kfree(event);
0270 return ERR_PTR(err);
0271 }
0272
0273 static void sdei_event_destroy_llocked(struct sdei_event *event)
0274 {
0275 lockdep_assert_held(&sdei_events_lock);
0276 lockdep_assert_held(&sdei_list_lock);
0277
0278 list_del(&event->list);
0279
0280 if (event->type == SDEI_EVENT_TYPE_SHARED)
0281 kfree(event->registered);
0282 else
0283 free_percpu(event->private_registered);
0284
0285 kfree(event);
0286 }
0287
0288 static void sdei_event_destroy(struct sdei_event *event)
0289 {
0290 spin_lock(&sdei_list_lock);
0291 sdei_event_destroy_llocked(event);
0292 spin_unlock(&sdei_list_lock);
0293 }
0294
0295 static int sdei_api_get_version(u64 *version)
0296 {
0297 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version);
0298 }
0299
0300 int sdei_mask_local_cpu(void)
0301 {
0302 int err;
0303
0304 WARN_ON_ONCE(preemptible());
0305
0306 err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL);
0307 if (err && err != -EIO) {
0308 pr_warn_once("failed to mask CPU[%u]: %d\n",
0309 smp_processor_id(), err);
0310 return err;
0311 }
0312
0313 return 0;
0314 }
0315
0316 static void _ipi_mask_cpu(void *ignored)
0317 {
0318 sdei_mask_local_cpu();
0319 }
0320
0321 int sdei_unmask_local_cpu(void)
0322 {
0323 int err;
0324
0325 WARN_ON_ONCE(preemptible());
0326
0327 err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL);
0328 if (err && err != -EIO) {
0329 pr_warn_once("failed to unmask CPU[%u]: %d\n",
0330 smp_processor_id(), err);
0331 return err;
0332 }
0333
0334 return 0;
0335 }
0336
0337 static void _ipi_unmask_cpu(void *ignored)
0338 {
0339 sdei_unmask_local_cpu();
0340 }
0341
0342 static void _ipi_private_reset(void *ignored)
0343 {
0344 int err;
0345
0346 err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0,
0347 NULL);
0348 if (err && err != -EIO)
0349 pr_warn_once("failed to reset CPU[%u]: %d\n",
0350 smp_processor_id(), err);
0351 }
0352
0353 static int sdei_api_shared_reset(void)
0354 {
0355 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_SHARED_RESET, 0, 0, 0, 0, 0,
0356 NULL);
0357 }
0358
0359 static void sdei_mark_interface_broken(void)
0360 {
0361 pr_err("disabling SDEI firmware interface\n");
0362 on_each_cpu(&_ipi_mask_cpu, NULL, true);
0363 sdei_firmware_call = NULL;
0364 }
0365
0366 static int sdei_platform_reset(void)
0367 {
0368 int err;
0369
0370 on_each_cpu(&_ipi_private_reset, NULL, true);
0371 err = sdei_api_shared_reset();
0372 if (err) {
0373 pr_err("Failed to reset platform: %d\n", err);
0374 sdei_mark_interface_broken();
0375 }
0376
0377 return err;
0378 }
0379
0380 static int sdei_api_event_enable(u32 event_num)
0381 {
0382 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ENABLE, event_num, 0, 0, 0,
0383 0, NULL);
0384 }
0385
0386
0387 static void _local_event_enable(void *data)
0388 {
0389 int err;
0390 struct sdei_crosscall_args *arg = data;
0391
0392 WARN_ON_ONCE(preemptible());
0393
0394 err = sdei_api_event_enable(arg->event->event_num);
0395
0396 sdei_cross_call_return(arg, err);
0397 }
0398
0399 int sdei_event_enable(u32 event_num)
0400 {
0401 int err = -EINVAL;
0402 struct sdei_event *event;
0403
0404 mutex_lock(&sdei_events_lock);
0405 event = sdei_event_find(event_num);
0406 if (!event) {
0407 mutex_unlock(&sdei_events_lock);
0408 return -ENOENT;
0409 }
0410
0411
0412 cpus_read_lock();
0413 if (event->type == SDEI_EVENT_TYPE_SHARED)
0414 err = sdei_api_event_enable(event->event_num);
0415 else
0416 err = sdei_do_cross_call(_local_event_enable, event);
0417
0418 if (!err) {
0419 spin_lock(&sdei_list_lock);
0420 event->reenable = true;
0421 spin_unlock(&sdei_list_lock);
0422 }
0423 cpus_read_unlock();
0424 mutex_unlock(&sdei_events_lock);
0425
0426 return err;
0427 }
0428
0429 static int sdei_api_event_disable(u32 event_num)
0430 {
0431 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_DISABLE, event_num, 0, 0,
0432 0, 0, NULL);
0433 }
0434
0435 static void _ipi_event_disable(void *data)
0436 {
0437 int err;
0438 struct sdei_crosscall_args *arg = data;
0439
0440 err = sdei_api_event_disable(arg->event->event_num);
0441
0442 sdei_cross_call_return(arg, err);
0443 }
0444
0445 int sdei_event_disable(u32 event_num)
0446 {
0447 int err = -EINVAL;
0448 struct sdei_event *event;
0449
0450 mutex_lock(&sdei_events_lock);
0451 event = sdei_event_find(event_num);
0452 if (!event) {
0453 mutex_unlock(&sdei_events_lock);
0454 return -ENOENT;
0455 }
0456
0457 spin_lock(&sdei_list_lock);
0458 event->reenable = false;
0459 spin_unlock(&sdei_list_lock);
0460
0461 if (event->type == SDEI_EVENT_TYPE_SHARED)
0462 err = sdei_api_event_disable(event->event_num);
0463 else
0464 err = sdei_do_cross_call(_ipi_event_disable, event);
0465 mutex_unlock(&sdei_events_lock);
0466
0467 return err;
0468 }
0469
0470 static int sdei_api_event_unregister(u32 event_num)
0471 {
0472 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_UNREGISTER, event_num, 0,
0473 0, 0, 0, NULL);
0474 }
0475
0476
0477 static void _local_event_unregister(void *data)
0478 {
0479 int err;
0480 struct sdei_crosscall_args *arg = data;
0481
0482 WARN_ON_ONCE(preemptible());
0483
0484 err = sdei_api_event_unregister(arg->event->event_num);
0485
0486 sdei_cross_call_return(arg, err);
0487 }
0488
0489 int sdei_event_unregister(u32 event_num)
0490 {
0491 int err;
0492 struct sdei_event *event;
0493
0494 WARN_ON(in_nmi());
0495
0496 mutex_lock(&sdei_events_lock);
0497 event = sdei_event_find(event_num);
0498 if (!event) {
0499 pr_warn("Event %u not registered\n", event_num);
0500 err = -ENOENT;
0501 goto unlock;
0502 }
0503
0504 spin_lock(&sdei_list_lock);
0505 event->reregister = false;
0506 event->reenable = false;
0507 spin_unlock(&sdei_list_lock);
0508
0509 if (event->type == SDEI_EVENT_TYPE_SHARED)
0510 err = sdei_api_event_unregister(event->event_num);
0511 else
0512 err = sdei_do_cross_call(_local_event_unregister, event);
0513
0514 if (err)
0515 goto unlock;
0516
0517 sdei_event_destroy(event);
0518 unlock:
0519 mutex_unlock(&sdei_events_lock);
0520
0521 return err;
0522 }
0523
0524
0525
0526
0527
0528 static int sdei_unregister_shared(void)
0529 {
0530 int err = 0;
0531 struct sdei_event *event;
0532
0533 mutex_lock(&sdei_events_lock);
0534 spin_lock(&sdei_list_lock);
0535 list_for_each_entry(event, &sdei_list, list) {
0536 if (event->type != SDEI_EVENT_TYPE_SHARED)
0537 continue;
0538
0539 err = sdei_api_event_unregister(event->event_num);
0540 if (err)
0541 break;
0542 }
0543 spin_unlock(&sdei_list_lock);
0544 mutex_unlock(&sdei_events_lock);
0545
0546 return err;
0547 }
0548
0549 static int sdei_api_event_register(u32 event_num, unsigned long entry_point,
0550 void *arg, u64 flags, u64 affinity)
0551 {
0552 return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_REGISTER, event_num,
0553 (unsigned long)entry_point, (unsigned long)arg,
0554 flags, affinity, NULL);
0555 }
0556
0557
0558 static void _local_event_register(void *data)
0559 {
0560 int err;
0561 struct sdei_registered_event *reg;
0562 struct sdei_crosscall_args *arg = data;
0563
0564 WARN_ON(preemptible());
0565
0566 reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id());
0567 err = sdei_api_event_register(arg->event->event_num, sdei_entry_point,
0568 reg, 0, 0);
0569
0570 sdei_cross_call_return(arg, err);
0571 }
0572
0573 int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
0574 {
0575 int err;
0576 struct sdei_event *event;
0577
0578 WARN_ON(in_nmi());
0579
0580 mutex_lock(&sdei_events_lock);
0581 if (sdei_event_find(event_num)) {
0582 pr_warn("Event %u already registered\n", event_num);
0583 err = -EBUSY;
0584 goto unlock;
0585 }
0586
0587 event = sdei_event_create(event_num, cb, arg);
0588 if (IS_ERR(event)) {
0589 err = PTR_ERR(event);
0590 pr_warn("Failed to create event %u: %d\n", event_num, err);
0591 goto unlock;
0592 }
0593
0594 cpus_read_lock();
0595 if (event->type == SDEI_EVENT_TYPE_SHARED) {
0596 err = sdei_api_event_register(event->event_num,
0597 sdei_entry_point,
0598 event->registered,
0599 SDEI_EVENT_REGISTER_RM_ANY, 0);
0600 } else {
0601 err = sdei_do_cross_call(_local_event_register, event);
0602 if (err)
0603 sdei_do_cross_call(_local_event_unregister, event);
0604 }
0605
0606 if (err) {
0607 sdei_event_destroy(event);
0608 pr_warn("Failed to register event %u: %d\n", event_num, err);
0609 goto cpu_unlock;
0610 }
0611
0612 spin_lock(&sdei_list_lock);
0613 event->reregister = true;
0614 spin_unlock(&sdei_list_lock);
0615 cpu_unlock:
0616 cpus_read_unlock();
0617 unlock:
0618 mutex_unlock(&sdei_events_lock);
0619 return err;
0620 }
0621
0622 static int sdei_reregister_shared(void)
0623 {
0624 int err = 0;
0625 struct sdei_event *event;
0626
0627 mutex_lock(&sdei_events_lock);
0628 spin_lock(&sdei_list_lock);
0629 list_for_each_entry(event, &sdei_list, list) {
0630 if (event->type != SDEI_EVENT_TYPE_SHARED)
0631 continue;
0632
0633 if (event->reregister) {
0634 err = sdei_api_event_register(event->event_num,
0635 sdei_entry_point, event->registered,
0636 SDEI_EVENT_REGISTER_RM_ANY, 0);
0637 if (err) {
0638 pr_err("Failed to re-register event %u\n",
0639 event->event_num);
0640 sdei_event_destroy_llocked(event);
0641 break;
0642 }
0643 }
0644
0645 if (event->reenable) {
0646 err = sdei_api_event_enable(event->event_num);
0647 if (err) {
0648 pr_err("Failed to re-enable event %u\n",
0649 event->event_num);
0650 break;
0651 }
0652 }
0653 }
0654 spin_unlock(&sdei_list_lock);
0655 mutex_unlock(&sdei_events_lock);
0656
0657 return err;
0658 }
0659
0660 static int sdei_cpuhp_down(unsigned int cpu)
0661 {
0662 struct sdei_event *event;
0663 int err;
0664
0665
0666 spin_lock(&sdei_list_lock);
0667 list_for_each_entry(event, &sdei_list, list) {
0668 if (event->type == SDEI_EVENT_TYPE_SHARED)
0669 continue;
0670
0671 err = sdei_do_local_call(_local_event_unregister, event);
0672 if (err) {
0673 pr_err("Failed to unregister event %u: %d\n",
0674 event->event_num, err);
0675 }
0676 }
0677 spin_unlock(&sdei_list_lock);
0678
0679 return sdei_mask_local_cpu();
0680 }
0681
0682 static int sdei_cpuhp_up(unsigned int cpu)
0683 {
0684 struct sdei_event *event;
0685 int err;
0686
0687
0688 spin_lock(&sdei_list_lock);
0689 list_for_each_entry(event, &sdei_list, list) {
0690 if (event->type == SDEI_EVENT_TYPE_SHARED)
0691 continue;
0692
0693 if (event->reregister) {
0694 err = sdei_do_local_call(_local_event_register, event);
0695 if (err) {
0696 pr_err("Failed to re-register event %u: %d\n",
0697 event->event_num, err);
0698 }
0699 }
0700
0701 if (event->reenable) {
0702 err = sdei_do_local_call(_local_event_enable, event);
0703 if (err) {
0704 pr_err("Failed to re-enable event %u: %d\n",
0705 event->event_num, err);
0706 }
0707 }
0708 }
0709 spin_unlock(&sdei_list_lock);
0710
0711 return sdei_unmask_local_cpu();
0712 }
0713
0714
0715 static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action,
0716 void *data)
0717 {
0718 int rv;
0719
0720 switch (action) {
0721 case CPU_PM_ENTER:
0722 rv = sdei_mask_local_cpu();
0723 break;
0724 case CPU_PM_EXIT:
0725 case CPU_PM_ENTER_FAILED:
0726 rv = sdei_unmask_local_cpu();
0727 break;
0728 default:
0729 return NOTIFY_DONE;
0730 }
0731
0732 if (rv)
0733 return notifier_from_errno(rv);
0734
0735 return NOTIFY_OK;
0736 }
0737
0738 static struct notifier_block sdei_pm_nb = {
0739 .notifier_call = sdei_pm_notifier,
0740 };
0741
0742 static int sdei_device_suspend(struct device *dev)
0743 {
0744 on_each_cpu(_ipi_mask_cpu, NULL, true);
0745
0746 return 0;
0747 }
0748
0749 static int sdei_device_resume(struct device *dev)
0750 {
0751 on_each_cpu(_ipi_unmask_cpu, NULL, true);
0752
0753 return 0;
0754 }
0755
0756
0757
0758
0759
0760
0761
0762
0763 static int sdei_device_freeze(struct device *dev)
0764 {
0765 int err;
0766
0767
0768 cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
0769
0770 err = sdei_unregister_shared();
0771 if (err)
0772 return err;
0773
0774 return 0;
0775 }
0776
0777 static int sdei_device_thaw(struct device *dev)
0778 {
0779 int err;
0780
0781
0782 err = sdei_reregister_shared();
0783 if (err) {
0784 pr_warn("Failed to re-register shared events...\n");
0785 sdei_mark_interface_broken();
0786 return err;
0787 }
0788
0789 err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
0790 &sdei_cpuhp_up, &sdei_cpuhp_down);
0791 if (err)
0792 pr_warn("Failed to re-register CPU hotplug notifier...\n");
0793
0794 return err;
0795 }
0796
0797 static int sdei_device_restore(struct device *dev)
0798 {
0799 int err;
0800
0801 err = sdei_platform_reset();
0802 if (err)
0803 return err;
0804
0805 return sdei_device_thaw(dev);
0806 }
0807
0808 static const struct dev_pm_ops sdei_pm_ops = {
0809 .suspend = sdei_device_suspend,
0810 .resume = sdei_device_resume,
0811 .freeze = sdei_device_freeze,
0812 .thaw = sdei_device_thaw,
0813 .restore = sdei_device_restore,
0814 };
0815
0816
0817
0818
0819 static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action,
0820 void *data)
0821 {
0822
0823
0824
0825
0826 cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING);
0827
0828 sdei_platform_reset();
0829
0830 return NOTIFY_OK;
0831 }
0832
0833 static struct notifier_block sdei_reboot_nb = {
0834 .notifier_call = sdei_reboot_notifier,
0835 };
0836
0837 static void sdei_smccc_smc(unsigned long function_id,
0838 unsigned long arg0, unsigned long arg1,
0839 unsigned long arg2, unsigned long arg3,
0840 unsigned long arg4, struct arm_smccc_res *res)
0841 {
0842 arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
0843 }
0844 NOKPROBE_SYMBOL(sdei_smccc_smc);
0845
0846 static void sdei_smccc_hvc(unsigned long function_id,
0847 unsigned long arg0, unsigned long arg1,
0848 unsigned long arg2, unsigned long arg3,
0849 unsigned long arg4, struct arm_smccc_res *res)
0850 {
0851 arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
0852 }
0853 NOKPROBE_SYMBOL(sdei_smccc_hvc);
0854
0855 int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
0856 sdei_event_callback *critical_cb)
0857 {
0858 int err;
0859 u64 result;
0860 u32 event_num;
0861 sdei_event_callback *cb;
0862
0863 if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
0864 return -EOPNOTSUPP;
0865
0866 event_num = ghes->generic->notify.vector;
0867 if (event_num == 0) {
0868
0869
0870
0871
0872 return -EINVAL;
0873 }
0874
0875 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
0876 &result);
0877 if (err)
0878 return err;
0879
0880 if (result == SDEI_EVENT_PRIORITY_CRITICAL)
0881 cb = critical_cb;
0882 else
0883 cb = normal_cb;
0884
0885 err = sdei_event_register(event_num, cb, ghes);
0886 if (!err)
0887 err = sdei_event_enable(event_num);
0888
0889 return err;
0890 }
0891
0892 int sdei_unregister_ghes(struct ghes *ghes)
0893 {
0894 int i;
0895 int err;
0896 u32 event_num = ghes->generic->notify.vector;
0897
0898 might_sleep();
0899
0900 if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
0901 return -EOPNOTSUPP;
0902
0903
0904
0905
0906
0907 err = sdei_event_disable(event_num);
0908 if (err)
0909 return err;
0910
0911 for (i = 0; i < 3; i++) {
0912 err = sdei_event_unregister(event_num);
0913 if (err != -EINPROGRESS)
0914 break;
0915
0916 schedule();
0917 }
0918
0919 return err;
0920 }
0921
0922 static int sdei_get_conduit(struct platform_device *pdev)
0923 {
0924 const char *method;
0925 struct device_node *np = pdev->dev.of_node;
0926
0927 sdei_firmware_call = NULL;
0928 if (np) {
0929 if (of_property_read_string(np, "method", &method)) {
0930 pr_warn("missing \"method\" property\n");
0931 return SMCCC_CONDUIT_NONE;
0932 }
0933
0934 if (!strcmp("hvc", method)) {
0935 sdei_firmware_call = &sdei_smccc_hvc;
0936 return SMCCC_CONDUIT_HVC;
0937 } else if (!strcmp("smc", method)) {
0938 sdei_firmware_call = &sdei_smccc_smc;
0939 return SMCCC_CONDUIT_SMC;
0940 }
0941
0942 pr_warn("invalid \"method\" property: %s\n", method);
0943 } else if (!acpi_disabled) {
0944 if (acpi_psci_use_hvc()) {
0945 sdei_firmware_call = &sdei_smccc_hvc;
0946 return SMCCC_CONDUIT_HVC;
0947 } else {
0948 sdei_firmware_call = &sdei_smccc_smc;
0949 return SMCCC_CONDUIT_SMC;
0950 }
0951 }
0952
0953 return SMCCC_CONDUIT_NONE;
0954 }
0955
0956 static int sdei_probe(struct platform_device *pdev)
0957 {
0958 int err;
0959 u64 ver = 0;
0960 int conduit;
0961
0962 conduit = sdei_get_conduit(pdev);
0963 if (!sdei_firmware_call)
0964 return 0;
0965
0966 err = sdei_api_get_version(&ver);
0967 if (err) {
0968 pr_err("Failed to get SDEI version: %d\n", err);
0969 sdei_mark_interface_broken();
0970 return err;
0971 }
0972
0973 pr_info("SDEIv%d.%d (0x%x) detected in firmware.\n",
0974 (int)SDEI_VERSION_MAJOR(ver), (int)SDEI_VERSION_MINOR(ver),
0975 (int)SDEI_VERSION_VENDOR(ver));
0976
0977 if (SDEI_VERSION_MAJOR(ver) != 1) {
0978 pr_warn("Conflicting SDEI version detected.\n");
0979 sdei_mark_interface_broken();
0980 return -EINVAL;
0981 }
0982
0983 err = sdei_platform_reset();
0984 if (err)
0985 return err;
0986
0987 sdei_entry_point = sdei_arch_get_entry_point(conduit);
0988 if (!sdei_entry_point) {
0989
0990 sdei_mark_interface_broken();
0991 return 0;
0992 }
0993
0994 err = cpu_pm_register_notifier(&sdei_pm_nb);
0995 if (err) {
0996 pr_warn("Failed to register CPU PM notifier...\n");
0997 goto error;
0998 }
0999
1000 err = register_reboot_notifier(&sdei_reboot_nb);
1001 if (err) {
1002 pr_warn("Failed to register reboot notifier...\n");
1003 goto remove_cpupm;
1004 }
1005
1006 err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI",
1007 &sdei_cpuhp_up, &sdei_cpuhp_down);
1008 if (err) {
1009 pr_warn("Failed to register CPU hotplug notifier...\n");
1010 goto remove_reboot;
1011 }
1012
1013 return 0;
1014
1015 remove_reboot:
1016 unregister_reboot_notifier(&sdei_reboot_nb);
1017
1018 remove_cpupm:
1019 cpu_pm_unregister_notifier(&sdei_pm_nb);
1020
1021 error:
1022 sdei_mark_interface_broken();
1023 return err;
1024 }
1025
1026 static const struct of_device_id sdei_of_match[] = {
1027 { .compatible = "arm,sdei-1.0" },
1028 {}
1029 };
1030
1031 static struct platform_driver sdei_driver = {
1032 .driver = {
1033 .name = "sdei",
1034 .pm = &sdei_pm_ops,
1035 .of_match_table = sdei_of_match,
1036 },
1037 .probe = sdei_probe,
1038 };
1039
1040 static bool __init sdei_present_acpi(void)
1041 {
1042 acpi_status status;
1043 struct acpi_table_header *sdei_table_header;
1044
1045 if (acpi_disabled)
1046 return false;
1047
1048 status = acpi_get_table(ACPI_SIG_SDEI, 0, &sdei_table_header);
1049 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
1050 const char *msg = acpi_format_exception(status);
1051
1052 pr_info("Failed to get ACPI:SDEI table, %s\n", msg);
1053 }
1054 if (ACPI_FAILURE(status))
1055 return false;
1056
1057 acpi_put_table(sdei_table_header);
1058
1059 return true;
1060 }
1061
1062 void __init sdei_init(void)
1063 {
1064 struct platform_device *pdev;
1065 int ret;
1066
1067 ret = platform_driver_register(&sdei_driver);
1068 if (ret || !sdei_present_acpi())
1069 return;
1070
1071 pdev = platform_device_register_simple(sdei_driver.driver.name,
1072 0, NULL, 0);
1073 if (IS_ERR(pdev)) {
1074 ret = PTR_ERR(pdev);
1075 platform_driver_unregister(&sdei_driver);
1076 pr_info("Failed to register ACPI:SDEI platform device %d\n",
1077 ret);
1078 }
1079 }
1080
1081 int sdei_event_handler(struct pt_regs *regs,
1082 struct sdei_registered_event *arg)
1083 {
1084 int err;
1085 u32 event_num = arg->event_num;
1086
1087 err = arg->callback(event_num, regs, arg->callback_arg);
1088 if (err)
1089 pr_err_ratelimited("event %u on CPU %u failed with error: %d\n",
1090 event_num, smp_processor_id(), err);
1091
1092 return err;
1093 }
1094 NOKPROBE_SYMBOL(sdei_event_handler);