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