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