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