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 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 } 46 static 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 64 static 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 78 static 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 98 static 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 111 arch_initcall(setup_vcpu_hotplug_event); 112 113