1283c0972SJoe Perches #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 2283c0972SJoe Perches 3d68d82afSAlex Nixon #include <linux/notifier.h> 4d68d82afSAlex Nixon 51ccbf534SJeremy Fitzhardinge #include <xen/xen.h> 6d68d82afSAlex Nixon #include <xen/xenbus.h> 7d68d82afSAlex Nixon 8bb898558SAl Viro #include <asm/xen/hypervisor.h> 9d68d82afSAlex Nixon #include <asm/cpu.h> 10d68d82afSAlex Nixon 11d68d82afSAlex Nixon static void enable_hotplug_cpu(int cpu) 12d68d82afSAlex Nixon { 13d68d82afSAlex Nixon if (!cpu_present(cpu)) 14a314e3ebSStefano Stabellini xen_arch_register_cpu(cpu); 15d68d82afSAlex Nixon 16d680eb8bSRusty Russell set_cpu_present(cpu, true); 17d68d82afSAlex Nixon } 18d68d82afSAlex Nixon 19d68d82afSAlex Nixon static void disable_hotplug_cpu(int cpu) 20d68d82afSAlex Nixon { 211c7a6213SStefano Stabellini if (cpu_online(cpu)) { 221c7a6213SStefano Stabellini lock_device_hotplug(); 231c7a6213SStefano Stabellini device_offline(get_cpu_device(cpu)); 241c7a6213SStefano Stabellini unlock_device_hotplug(); 251c7a6213SStefano Stabellini } 26d68d82afSAlex Nixon if (cpu_present(cpu)) 27a314e3ebSStefano Stabellini xen_arch_unregister_cpu(cpu); 28d68d82afSAlex Nixon 29d680eb8bSRusty Russell set_cpu_present(cpu, false); 30d68d82afSAlex Nixon } 31d68d82afSAlex Nixon 32d745562cSIan Campbell static int vcpu_online(unsigned int cpu) 33d68d82afSAlex Nixon { 34d68d82afSAlex Nixon int err; 35e5c702d3SJan Beulich char dir[16], state[16]; 36d68d82afSAlex Nixon 37d68d82afSAlex Nixon sprintf(dir, "cpu/%u", cpu); 38e5c702d3SJan Beulich err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state); 39d68d82afSAlex Nixon if (err != 1) { 405b02aa1eSKonrad Rzeszutek Wilk if (!xen_initial_domain()) 41283c0972SJoe Perches pr_err("Unable to read cpu state\n"); 42d745562cSIan Campbell return err; 43d68d82afSAlex Nixon } 44d68d82afSAlex Nixon 45d745562cSIan Campbell if (strcmp(state, "online") == 0) 46d745562cSIan Campbell return 1; 47d745562cSIan Campbell else if (strcmp(state, "offline") == 0) 48d745562cSIan Campbell return 0; 49d745562cSIan Campbell 50283c0972SJoe Perches pr_err("unknown state(%s) on CPU%d\n", state, cpu); 51d745562cSIan Campbell return -EINVAL; 52d745562cSIan Campbell } 53d745562cSIan Campbell static void vcpu_hotplug(unsigned int cpu) 54d745562cSIan Campbell { 55d745562cSIan Campbell if (!cpu_possible(cpu)) 56d745562cSIan Campbell return; 57d745562cSIan Campbell 58d745562cSIan Campbell switch (vcpu_online(cpu)) { 59d745562cSIan Campbell case 1: 60d68d82afSAlex Nixon enable_hotplug_cpu(cpu); 61d745562cSIan Campbell break; 62d745562cSIan Campbell case 0: 63d68d82afSAlex Nixon disable_hotplug_cpu(cpu); 64d745562cSIan Campbell break; 65d745562cSIan Campbell default: 66d745562cSIan Campbell break; 67d68d82afSAlex Nixon } 68d68d82afSAlex Nixon } 69d68d82afSAlex Nixon 70d68d82afSAlex Nixon static void handle_vcpu_hotplug_event(struct xenbus_watch *watch, 71d68d82afSAlex Nixon const char **vec, unsigned int len) 72d68d82afSAlex Nixon { 73d68d82afSAlex Nixon unsigned int cpu; 74d68d82afSAlex Nixon char *cpustr; 75d68d82afSAlex Nixon const char *node = vec[XS_WATCH_PATH]; 76d68d82afSAlex Nixon 77d68d82afSAlex Nixon cpustr = strstr(node, "cpu/"); 78d68d82afSAlex Nixon if (cpustr != NULL) { 79d68d82afSAlex Nixon sscanf(cpustr, "cpu/%u", &cpu); 80d68d82afSAlex Nixon vcpu_hotplug(cpu); 81d68d82afSAlex Nixon } 82d68d82afSAlex Nixon } 83d68d82afSAlex Nixon 84d68d82afSAlex Nixon static int setup_cpu_watcher(struct notifier_block *notifier, 85d68d82afSAlex Nixon unsigned long event, void *data) 86d68d82afSAlex Nixon { 87d745562cSIan Campbell int cpu; 88d68d82afSAlex Nixon static struct xenbus_watch cpu_watch = { 89d68d82afSAlex Nixon .node = "cpu", 90d68d82afSAlex Nixon .callback = handle_vcpu_hotplug_event}; 91d68d82afSAlex Nixon 92d68d82afSAlex Nixon (void)register_xenbus_watch(&cpu_watch); 93d68d82afSAlex Nixon 94d745562cSIan Campbell for_each_possible_cpu(cpu) { 95d745562cSIan Campbell if (vcpu_online(cpu) == 0) { 96d745562cSIan Campbell (void)cpu_down(cpu); 97d7d3756cSRusty Russell set_cpu_present(cpu, false); 98d745562cSIan Campbell } 99d745562cSIan Campbell } 100d745562cSIan Campbell 101d68d82afSAlex Nixon return NOTIFY_DONE; 102d68d82afSAlex Nixon } 103d68d82afSAlex Nixon 104d68d82afSAlex Nixon static int __init setup_vcpu_hotplug_event(void) 105d68d82afSAlex Nixon { 106d68d82afSAlex Nixon static struct notifier_block xsn_cpu = { 107d68d82afSAlex Nixon .notifier_call = setup_cpu_watcher }; 108d68d82afSAlex Nixon 109a314e3ebSStefano Stabellini #ifdef CONFIG_X86 110*2a7197f0SBoris Ostrovsky if (!xen_pv_domain() && !xen_pvh_domain()) 111a314e3ebSStefano Stabellini #else 112a314e3ebSStefano Stabellini if (!xen_domain()) 113a314e3ebSStefano Stabellini #endif 114d68d82afSAlex Nixon return -ENODEV; 115d68d82afSAlex Nixon 116d68d82afSAlex Nixon register_xenstore_notifier(&xsn_cpu); 117d68d82afSAlex Nixon 118d68d82afSAlex Nixon return 0; 119d68d82afSAlex Nixon } 120d68d82afSAlex Nixon 121d68d82afSAlex Nixon arch_initcall(setup_vcpu_hotplug_event); 122d68d82afSAlex Nixon 123