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