cpu_hotplug.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
  3. #include <linux/notifier.h>
  4. #include <xen/xen.h>
  5. #include <xen/xenbus.h>
  6. #include <asm/xen/hypervisor.h>
  7. #include <asm/cpu.h>
  8. static void enable_hotplug_cpu(int cpu)
  9. {
  10. if (!cpu_present(cpu))
  11. xen_arch_register_cpu(cpu);
  12. set_cpu_present(cpu, true);
  13. }
  14. static void disable_hotplug_cpu(int cpu)
  15. {
  16. if (!cpu_is_hotpluggable(cpu))
  17. return;
  18. lock_device_hotplug();
  19. if (cpu_online(cpu))
  20. device_offline(get_cpu_device(cpu));
  21. if (!cpu_online(cpu) && cpu_present(cpu)) {
  22. xen_arch_unregister_cpu(cpu);
  23. set_cpu_present(cpu, false);
  24. }
  25. unlock_device_hotplug();
  26. }
  27. static int vcpu_online(unsigned int cpu)
  28. {
  29. int err;
  30. char dir[16], state[16];
  31. sprintf(dir, "cpu/%u", cpu);
  32. err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
  33. if (err != 1) {
  34. if (!xen_initial_domain())
  35. pr_err("Unable to read cpu state\n");
  36. return err;
  37. }
  38. if (strcmp(state, "online") == 0)
  39. return 1;
  40. else if (strcmp(state, "offline") == 0)
  41. return 0;
  42. pr_err("unknown state(%s) on CPU%d\n", state, cpu);
  43. return -EINVAL;
  44. }
  45. static void vcpu_hotplug(unsigned int cpu)
  46. {
  47. if (cpu >= nr_cpu_ids || !cpu_possible(cpu))
  48. return;
  49. switch (vcpu_online(cpu)) {
  50. case 1:
  51. enable_hotplug_cpu(cpu);
  52. break;
  53. case 0:
  54. disable_hotplug_cpu(cpu);
  55. break;
  56. default:
  57. break;
  58. }
  59. }
  60. static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
  61. const char *path, const char *token)
  62. {
  63. unsigned int cpu;
  64. char *cpustr;
  65. cpustr = strstr(path, "cpu/");
  66. if (cpustr != NULL) {
  67. sscanf(cpustr, "cpu/%u", &cpu);
  68. vcpu_hotplug(cpu);
  69. }
  70. }
  71. static int setup_cpu_watcher(struct notifier_block *notifier,
  72. unsigned long event, void *data)
  73. {
  74. int cpu;
  75. static struct xenbus_watch cpu_watch = {
  76. .node = "cpu",
  77. .callback = handle_vcpu_hotplug_event};
  78. (void)register_xenbus_watch(&cpu_watch);
  79. for_each_possible_cpu(cpu) {
  80. if (vcpu_online(cpu) == 0) {
  81. (void)cpu_down(cpu);
  82. set_cpu_present(cpu, false);
  83. }
  84. }
  85. return NOTIFY_DONE;
  86. }
  87. static int __init setup_vcpu_hotplug_event(void)
  88. {
  89. static struct notifier_block xsn_cpu = {
  90. .notifier_call = setup_cpu_watcher };
  91. #ifdef CONFIG_X86
  92. if (!xen_pv_domain() && !xen_pvh_domain())
  93. #else
  94. if (!xen_domain())
  95. #endif
  96. return -ENODEV;
  97. register_xenstore_notifier(&xsn_cpu);
  98. return 0;
  99. }
  100. arch_initcall(setup_vcpu_hotplug_event);