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