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