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