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