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