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