cpu_hotplug.c 2.2 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_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 **vec, unsigned int len)
  59. {
  60. unsigned int cpu;
  61. char *cpustr;
  62. const char *node = vec[XS_WATCH_PATH];
  63. cpustr = strstr(node, "cpu/");
  64. if (cpustr != NULL) {
  65. sscanf(cpustr, "cpu/%u", &cpu);
  66. vcpu_hotplug(cpu);
  67. }
  68. }
  69. static int setup_cpu_watcher(struct notifier_block *notifier,
  70. unsigned long event, void *data)
  71. {
  72. int cpu;
  73. static struct xenbus_watch cpu_watch = {
  74. .node = "cpu",
  75. .callback = handle_vcpu_hotplug_event};
  76. (void)register_xenbus_watch(&cpu_watch);
  77. for_each_possible_cpu(cpu) {
  78. if (vcpu_online(cpu) == 0) {
  79. (void)cpu_down(cpu);
  80. set_cpu_present(cpu, false);
  81. }
  82. }
  83. return NOTIFY_DONE;
  84. }
  85. static int __init setup_vcpu_hotplug_event(void)
  86. {
  87. static struct notifier_block xsn_cpu = {
  88. .notifier_call = setup_cpu_watcher };
  89. #ifdef CONFIG_X86
  90. if (!xen_pv_domain())
  91. #else
  92. if (!xen_domain())
  93. #endif
  94. return -ENODEV;
  95. register_xenstore_notifier(&xsn_cpu);
  96. return 0;
  97. }
  98. arch_initcall(setup_vcpu_hotplug_event);