cpu_hotplug.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
  2. #include <linux/notifier.h>
  3. #include <xen/xen.h>
  4. #include <xen/xenbus.h>
  5. #include <asm/xen/hypervisor.h>
  6. #include <asm/cpu.h>
  7. static void enable_hotplug_cpu(int cpu)
  8. {
  9. if (!cpu_present(cpu))
  10. xen_arch_register_cpu(cpu);
  11. set_cpu_present(cpu, true);
  12. }
  13. static void disable_hotplug_cpu(int cpu)
  14. {
  15. if (!cpu_is_hotpluggable(cpu))
  16. return;
  17. lock_device_hotplug();
  18. if (cpu_online(cpu))
  19. device_offline(get_cpu_device(cpu));
  20. if (!cpu_online(cpu) && cpu_present(cpu)) {
  21. xen_arch_unregister_cpu(cpu);
  22. set_cpu_present(cpu, false);
  23. }
  24. unlock_device_hotplug();
  25. }
  26. static int vcpu_online(unsigned int cpu)
  27. {
  28. int err;
  29. char dir[16], state[16];
  30. sprintf(dir, "cpu/%u", cpu);
  31. err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
  32. if (err != 1) {
  33. if (!xen_initial_domain())
  34. pr_err("Unable to read cpu state\n");
  35. return err;
  36. }
  37. if (strcmp(state, "online") == 0)
  38. return 1;
  39. else if (strcmp(state, "offline") == 0)
  40. return 0;
  41. pr_err("unknown state(%s) on CPU%d\n", state, cpu);
  42. return -EINVAL;
  43. }
  44. static void vcpu_hotplug(unsigned int cpu)
  45. {
  46. if (!cpu_possible(cpu))
  47. return;
  48. switch (vcpu_online(cpu)) {
  49. case 1:
  50. enable_hotplug_cpu(cpu);
  51. break;
  52. case 0:
  53. disable_hotplug_cpu(cpu);
  54. break;
  55. default:
  56. break;
  57. }
  58. }
  59. static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
  60. const char **vec, unsigned int len)
  61. {
  62. unsigned int cpu;
  63. char *cpustr;
  64. const char *node = vec[XS_WATCH_PATH];
  65. cpustr = strstr(node, "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())
  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);