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