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