Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gerg/m68knommu
[~shefty/rdma-dev.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                 if (!xen_initial_domain())
34                         printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
35                 return err;
36         }
37
38         if (strcmp(state, "online") == 0)
39                 return 1;
40         else if (strcmp(state, "offline") == 0)
41                 return 0;
42
43         printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n", state, cpu);
44         return -EINVAL;
45 }
46 static void vcpu_hotplug(unsigned int cpu)
47 {
48         if (!cpu_possible(cpu))
49                 return;
50
51         switch (vcpu_online(cpu)) {
52         case 1:
53                 enable_hotplug_cpu(cpu);
54                 break;
55         case 0:
56                 (void)cpu_down(cpu);
57                 disable_hotplug_cpu(cpu);
58                 break;
59         default:
60                 break;
61         }
62 }
63
64 static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
65                                         const char **vec, unsigned int len)
66 {
67         unsigned int cpu;
68         char *cpustr;
69         const char *node = vec[XS_WATCH_PATH];
70
71         cpustr = strstr(node, "cpu/");
72         if (cpustr != NULL) {
73                 sscanf(cpustr, "cpu/%u", &cpu);
74                 vcpu_hotplug(cpu);
75         }
76 }
77
78 static int setup_cpu_watcher(struct notifier_block *notifier,
79                               unsigned long event, void *data)
80 {
81         int cpu;
82         static struct xenbus_watch cpu_watch = {
83                 .node = "cpu",
84                 .callback = handle_vcpu_hotplug_event};
85
86         (void)register_xenbus_watch(&cpu_watch);
87
88         for_each_possible_cpu(cpu) {
89                 if (vcpu_online(cpu) == 0) {
90                         (void)cpu_down(cpu);
91                         set_cpu_present(cpu, false);
92                 }
93         }
94
95         return NOTIFY_DONE;
96 }
97
98 static int __init setup_vcpu_hotplug_event(void)
99 {
100         static struct notifier_block xsn_cpu = {
101                 .notifier_call = setup_cpu_watcher };
102
103         if (!xen_pv_domain())
104                 return -ENODEV;
105
106         register_xenstore_notifier(&xsn_cpu);
107
108         return 0;
109 }
110
111 arch_initcall(setup_vcpu_hotplug_event);
112