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 
enable_hotplug_cpu(int cpu)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 
disable_hotplug_cpu(int cpu)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 
vcpu_online(unsigned int cpu)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 }
vcpu_hotplug(unsigned int cpu)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 
handle_vcpu_hotplug_event(struct xenbus_watch * watch,const char ** vec,unsigned int len)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 
setup_cpu_watcher(struct notifier_block * notifier,unsigned long event,void * data)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 
setup_vcpu_hotplug_event(void)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