cpu_hotplug.c 2.2 KB

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