root/drivers/firmware/arm_sdei.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sdei_do_cross_call
  2. sdei_cross_call_return
  3. sdei_to_linux_errno
  4. sdei_is_err
  5. invoke_sdei_fn
  6. sdei_event_find
  7. sdei_api_event_context
  8. sdei_api_event_get_info
  9. sdei_event_create
  10. sdei_event_destroy
  11. sdei_api_get_version
  12. sdei_mask_local_cpu
  13. _ipi_mask_cpu
  14. sdei_unmask_local_cpu
  15. _ipi_unmask_cpu
  16. _ipi_private_reset
  17. sdei_api_shared_reset
  18. sdei_mark_interface_broken
  19. sdei_platform_reset
  20. sdei_api_event_enable
  21. _local_event_enable
  22. sdei_event_enable
  23. sdei_api_event_disable
  24. _ipi_event_disable
  25. sdei_event_disable
  26. sdei_api_event_unregister
  27. _local_event_unregister
  28. _sdei_event_unregister
  29. sdei_event_unregister
  30. sdei_unregister_shared
  31. sdei_api_event_register
  32. _local_event_register
  33. _sdei_event_register
  34. sdei_event_register
  35. sdei_reregister_event
  36. sdei_reregister_shared
  37. sdei_cpuhp_down
  38. sdei_cpuhp_up
  39. sdei_pm_notifier
  40. sdei_device_suspend
  41. sdei_device_resume
  42. sdei_device_freeze
  43. sdei_device_thaw
  44. sdei_device_restore
  45. sdei_reboot_notifier
  46. sdei_smccc_smc
  47. sdei_smccc_hvc
  48. sdei_register_ghes
  49. sdei_unregister_ghes
  50. sdei_get_conduit
  51. sdei_probe
  52. sdei_present_dt
  53. sdei_present_acpi
  54. sdei_init
  55. sdei_event_handler

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

/* [<][>][^][v][top][bottom][index][help] */