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