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