pvpanic.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Pvpanic Device Support
  4. *
  5. * Copyright (C) 2013 Fujitsu.
  6. * Copyright (C) 2018 ZTE.
  7. * Copyright (C) 2021 Oracle.
  8. */
  9. #include <linux/io.h>
  10. #include <linux/kernel.h>
  11. #include <linux/kexec.h>
  12. #include <linux/mod_devicetable.h>
  13. #include <linux/module.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/panic_notifier.h>
  16. #include <linux/types.h>
  17. #include <linux/cdev.h>
  18. #include <linux/list.h>
  19. #include <uapi/misc/pvpanic.h>
  20. #include "pvpanic.h"
  21. MODULE_AUTHOR("Mihai Carabas <[email protected]>");
  22. MODULE_DESCRIPTION("pvpanic device driver");
  23. MODULE_LICENSE("GPL");
  24. static struct list_head pvpanic_list;
  25. static spinlock_t pvpanic_lock;
  26. static void
  27. pvpanic_send_event(unsigned int event)
  28. {
  29. struct pvpanic_instance *pi_cur;
  30. if (!spin_trylock(&pvpanic_lock))
  31. return;
  32. list_for_each_entry(pi_cur, &pvpanic_list, list) {
  33. if (event & pi_cur->capability & pi_cur->events)
  34. iowrite8(event, pi_cur->base);
  35. }
  36. spin_unlock(&pvpanic_lock);
  37. }
  38. static int
  39. pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, void *unused)
  40. {
  41. unsigned int event = PVPANIC_PANICKED;
  42. if (kexec_crash_loaded())
  43. event = PVPANIC_CRASH_LOADED;
  44. pvpanic_send_event(event);
  45. return NOTIFY_DONE;
  46. }
  47. /*
  48. * Call our notifier very early on panic, deferring the
  49. * action taken to the hypervisor.
  50. */
  51. static struct notifier_block pvpanic_panic_nb = {
  52. .notifier_call = pvpanic_panic_notify,
  53. .priority = INT_MAX,
  54. };
  55. static void pvpanic_remove(void *param)
  56. {
  57. struct pvpanic_instance *pi_cur, *pi_next;
  58. struct pvpanic_instance *pi = param;
  59. spin_lock(&pvpanic_lock);
  60. list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) {
  61. if (pi_cur == pi) {
  62. list_del(&pi_cur->list);
  63. break;
  64. }
  65. }
  66. spin_unlock(&pvpanic_lock);
  67. }
  68. int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi)
  69. {
  70. if (!pi || !pi->base)
  71. return -EINVAL;
  72. spin_lock(&pvpanic_lock);
  73. list_add(&pi->list, &pvpanic_list);
  74. spin_unlock(&pvpanic_lock);
  75. dev_set_drvdata(dev, pi);
  76. return devm_add_action_or_reset(dev, pvpanic_remove, pi);
  77. }
  78. EXPORT_SYMBOL_GPL(devm_pvpanic_probe);
  79. static int pvpanic_init(void)
  80. {
  81. INIT_LIST_HEAD(&pvpanic_list);
  82. spin_lock_init(&pvpanic_lock);
  83. atomic_notifier_chain_register(&panic_notifier_list, &pvpanic_panic_nb);
  84. return 0;
  85. }
  86. module_init(pvpanic_init);
  87. static void pvpanic_exit(void)
  88. {
  89. atomic_notifier_chain_unregister(&panic_notifier_list, &pvpanic_panic_nb);
  90. }
  91. module_exit(pvpanic_exit);