at v4.18 2.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt 3 4#include <linux/notifier.h> 5 6#include <xen/xen.h> 7#include <xen/xenbus.h> 8 9#include <asm/xen/hypervisor.h> 10#include <asm/cpu.h> 11 12static void enable_hotplug_cpu(int cpu) 13{ 14 if (!cpu_present(cpu)) 15 xen_arch_register_cpu(cpu); 16 17 set_cpu_present(cpu, true); 18} 19 20static void disable_hotplug_cpu(int cpu) 21{ 22 if (cpu_online(cpu)) { 23 lock_device_hotplug(); 24 device_offline(get_cpu_device(cpu)); 25 unlock_device_hotplug(); 26 } 27 if (cpu_present(cpu)) 28 xen_arch_unregister_cpu(cpu); 29 30 set_cpu_present(cpu, false); 31} 32 33static int vcpu_online(unsigned int cpu) 34{ 35 int err; 36 char dir[16], state[16]; 37 38 sprintf(dir, "cpu/%u", cpu); 39 err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state); 40 if (err != 1) { 41 if (!xen_initial_domain()) 42 pr_err("Unable to read cpu state\n"); 43 return err; 44 } 45 46 if (strcmp(state, "online") == 0) 47 return 1; 48 else if (strcmp(state, "offline") == 0) 49 return 0; 50 51 pr_err("unknown state(%s) on CPU%d\n", state, cpu); 52 return -EINVAL; 53} 54static void vcpu_hotplug(unsigned int cpu) 55{ 56 if (!cpu_possible(cpu)) 57 return; 58 59 switch (vcpu_online(cpu)) { 60 case 1: 61 enable_hotplug_cpu(cpu); 62 break; 63 case 0: 64 disable_hotplug_cpu(cpu); 65 break; 66 default: 67 break; 68 } 69} 70 71static void handle_vcpu_hotplug_event(struct xenbus_watch *watch, 72 const char *path, const char *token) 73{ 74 unsigned int cpu; 75 char *cpustr; 76 77 cpustr = strstr(path, "cpu/"); 78 if (cpustr != NULL) { 79 sscanf(cpustr, "cpu/%u", &cpu); 80 vcpu_hotplug(cpu); 81 } 82} 83 84static int setup_cpu_watcher(struct notifier_block *notifier, 85 unsigned long event, void *data) 86{ 87 int cpu; 88 static struct xenbus_watch cpu_watch = { 89 .node = "cpu", 90 .callback = handle_vcpu_hotplug_event}; 91 92 (void)register_xenbus_watch(&cpu_watch); 93 94 for_each_possible_cpu(cpu) { 95 if (vcpu_online(cpu) == 0) { 96 (void)cpu_down(cpu); 97 set_cpu_present(cpu, false); 98 } 99 } 100 101 return NOTIFY_DONE; 102} 103 104static int __init setup_vcpu_hotplug_event(void) 105{ 106 static struct notifier_block xsn_cpu = { 107 .notifier_call = setup_cpu_watcher }; 108 109#ifdef CONFIG_X86 110 if (!xen_pv_domain() && !xen_pvh_domain()) 111#else 112 if (!xen_domain()) 113#endif 114 return -ENODEV; 115 116 register_xenstore_notifier(&xsn_cpu); 117 118 return 0; 119} 120 121arch_initcall(setup_vcpu_hotplug_event); 122