123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- // SPDX-License-Identifier: GPL-2.0
- #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
- #include <linux/notifier.h>
- #include <xen/xen.h>
- #include <xen/xenbus.h>
- #include <asm/xen/hypervisor.h>
- #include <asm/cpu.h>
- static void enable_hotplug_cpu(int cpu)
- {
- if (!cpu_present(cpu))
- xen_arch_register_cpu(cpu);
- set_cpu_present(cpu, true);
- }
- static void disable_hotplug_cpu(int cpu)
- {
- if (!cpu_is_hotpluggable(cpu))
- return;
- lock_device_hotplug();
- if (cpu_online(cpu))
- device_offline(get_cpu_device(cpu));
- if (!cpu_online(cpu) && cpu_present(cpu)) {
- xen_arch_unregister_cpu(cpu);
- set_cpu_present(cpu, false);
- }
- unlock_device_hotplug();
- }
- static int vcpu_online(unsigned int cpu)
- {
- int err;
- char dir[16], state[16];
- sprintf(dir, "cpu/%u", cpu);
- err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
- if (err != 1) {
- if (!xen_initial_domain())
- pr_err("Unable to read cpu state\n");
- return err;
- }
- if (strcmp(state, "online") == 0)
- return 1;
- else if (strcmp(state, "offline") == 0)
- return 0;
- pr_err("unknown state(%s) on CPU%d\n", state, cpu);
- return -EINVAL;
- }
- static void vcpu_hotplug(unsigned int cpu)
- {
- if (cpu >= nr_cpu_ids || !cpu_possible(cpu))
- return;
- switch (vcpu_online(cpu)) {
- case 1:
- enable_hotplug_cpu(cpu);
- break;
- case 0:
- disable_hotplug_cpu(cpu);
- break;
- default:
- break;
- }
- }
- static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
- const char *path, const char *token)
- {
- unsigned int cpu;
- char *cpustr;
- cpustr = strstr(path, "cpu/");
- if (cpustr != NULL) {
- sscanf(cpustr, "cpu/%u", &cpu);
- vcpu_hotplug(cpu);
- }
- }
- static int setup_cpu_watcher(struct notifier_block *notifier,
- unsigned long event, void *data)
- {
- int cpu;
- static struct xenbus_watch cpu_watch = {
- .node = "cpu",
- .callback = handle_vcpu_hotplug_event};
- (void)register_xenbus_watch(&cpu_watch);
- for_each_possible_cpu(cpu) {
- if (vcpu_online(cpu) == 0) {
- (void)cpu_down(cpu);
- set_cpu_present(cpu, false);
- }
- }
- return NOTIFY_DONE;
- }
- static int __init setup_vcpu_hotplug_event(void)
- {
- static struct notifier_block xsn_cpu = {
- .notifier_call = setup_cpu_watcher };
- #ifdef CONFIG_X86
- if (!xen_pv_domain() && !xen_pvh_domain())
- #else
- if (!xen_domain())
- #endif
- return -ENODEV;
- register_xenstore_notifier(&xsn_cpu);
- return 0;
- }
- arch_initcall(setup_vcpu_hotplug_event);
|