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