0001
0002 #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
0003
0004 #include <linux/notifier.h>
0005
0006 #include <xen/xen.h>
0007 #include <xen/xenbus.h>
0008
0009 #include <asm/xen/hypervisor.h>
0010 #include <asm/cpu.h>
0011
0012 static void enable_hotplug_cpu(int cpu)
0013 {
0014 if (!cpu_present(cpu))
0015 xen_arch_register_cpu(cpu);
0016
0017 set_cpu_present(cpu, true);
0018 }
0019
0020 static void disable_hotplug_cpu(int cpu)
0021 {
0022 if (!cpu_is_hotpluggable(cpu))
0023 return;
0024 lock_device_hotplug();
0025 if (cpu_online(cpu))
0026 device_offline(get_cpu_device(cpu));
0027 if (!cpu_online(cpu) && cpu_present(cpu)) {
0028 xen_arch_unregister_cpu(cpu);
0029 set_cpu_present(cpu, false);
0030 }
0031 unlock_device_hotplug();
0032 }
0033
0034 static int vcpu_online(unsigned int cpu)
0035 {
0036 int err;
0037 char dir[16], state[16];
0038
0039 sprintf(dir, "cpu/%u", cpu);
0040 err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
0041 if (err != 1) {
0042 if (!xen_initial_domain())
0043 pr_err("Unable to read cpu state\n");
0044 return err;
0045 }
0046
0047 if (strcmp(state, "online") == 0)
0048 return 1;
0049 else if (strcmp(state, "offline") == 0)
0050 return 0;
0051
0052 pr_err("unknown state(%s) on CPU%d\n", state, cpu);
0053 return -EINVAL;
0054 }
0055 static void vcpu_hotplug(unsigned int cpu)
0056 {
0057 if (cpu >= nr_cpu_ids || !cpu_possible(cpu))
0058 return;
0059
0060 switch (vcpu_online(cpu)) {
0061 case 1:
0062 enable_hotplug_cpu(cpu);
0063 break;
0064 case 0:
0065 disable_hotplug_cpu(cpu);
0066 break;
0067 default:
0068 break;
0069 }
0070 }
0071
0072 static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
0073 const char *path, const char *token)
0074 {
0075 unsigned int cpu;
0076 char *cpustr;
0077
0078 cpustr = strstr(path, "cpu/");
0079 if (cpustr != NULL) {
0080 sscanf(cpustr, "cpu/%u", &cpu);
0081 vcpu_hotplug(cpu);
0082 }
0083 }
0084
0085 static int setup_cpu_watcher(struct notifier_block *notifier,
0086 unsigned long event, void *data)
0087 {
0088 int cpu;
0089 static struct xenbus_watch cpu_watch = {
0090 .node = "cpu",
0091 .callback = handle_vcpu_hotplug_event};
0092
0093 (void)register_xenbus_watch(&cpu_watch);
0094
0095 for_each_possible_cpu(cpu) {
0096 if (vcpu_online(cpu) == 0)
0097 disable_hotplug_cpu(cpu);
0098 }
0099
0100 return NOTIFY_DONE;
0101 }
0102
0103 static int __init setup_vcpu_hotplug_event(void)
0104 {
0105 static struct notifier_block xsn_cpu = {
0106 .notifier_call = setup_cpu_watcher };
0107
0108 #ifdef CONFIG_X86
0109 if (!xen_pv_domain() && !xen_pvh_domain())
0110 #else
0111 if (!xen_domain())
0112 #endif
0113 return -ENODEV;
0114
0115 register_xenstore_notifier(&xsn_cpu);
0116
0117 return 0;
0118 }
0119
0120 late_initcall(setup_vcpu_hotplug_event);
0121