linux/drivers/xen/cpu_hotplug.c
<<
>>
Prefs
   1#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
   2
   3#include <linux/notifier.h>
   4
   5#include <xen/xen.h>
   6#include <xen/xenbus.h>
   7
   8#include <asm/xen/hypervisor.h>
   9#include <asm/cpu.h>
  10
  11static void enable_hotplug_cpu(int cpu)
  12{
  13        if (!cpu_present(cpu))
  14                xen_arch_register_cpu(cpu);
  15
  16        set_cpu_present(cpu, true);
  17}
  18
  19static void disable_hotplug_cpu(int cpu)
  20{
  21        if (cpu_online(cpu)) {
  22                lock_device_hotplug();
  23                device_offline(get_cpu_device(cpu));
  24                unlock_device_hotplug();
  25        }
  26        if (cpu_present(cpu))
  27                xen_arch_unregister_cpu(cpu);
  28
  29        set_cpu_present(cpu, false);
  30}
  31
  32static int vcpu_online(unsigned int cpu)
  33{
  34        int err;
  35        char dir[16], state[16];
  36
  37        sprintf(dir, "cpu/%u", cpu);
  38        err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
  39        if (err != 1) {
  40                if (!xen_initial_domain())
  41                        pr_err("Unable to read cpu state\n");
  42                return err;
  43        }
  44
  45        if (strcmp(state, "online") == 0)
  46                return 1;
  47        else if (strcmp(state, "offline") == 0)
  48                return 0;
  49
  50        pr_err("unknown state(%s) on CPU%d\n", state, cpu);
  51        return -EINVAL;
  52}
  53static void vcpu_hotplug(unsigned int cpu)
  54{
  55        if (!cpu_possible(cpu))
  56                return;
  57
  58        switch (vcpu_online(cpu)) {
  59        case 1:
  60                enable_hotplug_cpu(cpu);
  61                break;
  62        case 0:
  63                disable_hotplug_cpu(cpu);
  64                break;
  65        default:
  66                break;
  67        }
  68}
  69
  70static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
  71                                        const char **vec, unsigned int len)
  72{
  73        unsigned int cpu;
  74        char *cpustr;
  75        const char *node = vec[XS_WATCH_PATH];
  76
  77        cpustr = strstr(node, "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())
 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
 123