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