Merge remote-tracking branch 'lsk/v3.10/topic/arm64-topology' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / base / cpu.c
index fb10728f63721565d282e2298f2bf14641fb8f1e..3d48fc887ef4b3a3da1aadefaf9129578e3d1ef2 100644 (file)
@@ -25,6 +25,15 @@ EXPORT_SYMBOL_GPL(cpu_subsys);
 static DEFINE_PER_CPU(struct device *, cpu_sys_devices);
 
 #ifdef CONFIG_HOTPLUG_CPU
+static void change_cpu_under_node(struct cpu *cpu,
+                       unsigned int from_nid, unsigned int to_nid)
+{
+       int cpuid = cpu->dev.id;
+       unregister_cpu_under_node(cpuid, from_nid);
+       register_cpu_under_node(cpuid, to_nid);
+       cpu->node_id = to_nid;
+}
+
 static ssize_t show_online(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
@@ -39,17 +48,29 @@ static ssize_t __ref store_online(struct device *dev,
                                  const char *buf, size_t count)
 {
        struct cpu *cpu = container_of(dev, struct cpu, dev);
+       int cpuid = cpu->dev.id;
+       int from_nid, to_nid;
        ssize_t ret;
 
        cpu_hotplug_driver_lock();
        switch (buf[0]) {
        case '0':
-               ret = cpu_down(cpu->dev.id);
+               ret = cpu_down(cpuid);
                if (!ret)
                        kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
                break;
        case '1':
-               ret = cpu_up(cpu->dev.id);
+               from_nid = cpu_to_node(cpuid);
+               ret = cpu_up(cpuid);
+
+               /*
+                * When hot adding memory to memoryless node and enabling a cpu
+                * on the node, node number of the cpu may internally change.
+                */
+               to_nid = cpu_to_node(cpuid);
+               if (from_nid != to_nid)
+                       change_cpu_under_node(cpu, from_nid, to_nid);
+
                if (!ret)
                        kobject_uevent(&dev->kobj, KOBJ_ONLINE);
                break;
@@ -132,6 +153,17 @@ static ssize_t show_crash_notes(struct device *dev, struct device_attribute *att
        return rc;
 }
 static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL);
+
+static ssize_t show_crash_notes_size(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       ssize_t rc;
+
+       rc = sprintf(buf, "%zu\n", sizeof(note_buf_t));
+       return rc;
+}
+static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL);
 #endif
 
 /*
@@ -259,6 +291,9 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
 #ifdef CONFIG_KEXEC
        if (!error)
                error = device_create_file(&cpu->dev, &dev_attr_crash_notes);
+       if (!error)
+               error = device_create_file(&cpu->dev,
+                                          &dev_attr_crash_notes_size);
 #endif
        return error;
 }