This patch set is the kernel part of code for cpu hotplug.
I got a patch in upstream but not accepted by mainline, this patch emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful for testing ACPI based hot-plug on systems that don't have the necessary firmware support. With this patch, I can test the hot-add and hot-remove repeatly.
This patch set is intended to close the cpu hotplug related cards in JIRA, just for review purpose, *should not* pushed to our linaro acpi.
I have created an acpi-hotplug-next branch in our git tree for these patches.
This patch set includes 3 parts, the forst part is the kernel code, and the second is the ASL code fix, the third part is the boot wrapper.
Hanjun Guo (4): Revert "ARM64 / CPU hot-plug: Skeleton logic cpu online/offline for cpu hot-plug" ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing arm / ACPI: Remove __cpuinit and fix __init attribute location arm: fix cpu hot add failure
Mark Rutland (6): arm64: reorganise smp_enable_ops arm64: factor out spin-table boot method arm64: read enable-method for CPU0 arm64: add CPU_HOTPLUG infrastructure arm64: add PSCI CPU_OFF-based hotplug support HACK: arm64: dts: foundation: add PSCI data
arch/arm64/Kconfig | 2 +- arch/arm64/boot/dts/foundation-v8.dts | 19 +-- arch/arm64/include/asm/irq.h | 1 + arch/arm64/include/asm/smp.h | 46 +++++-- arch/arm64/kernel/cputable.c | 2 +- arch/arm64/kernel/head.S | 12 +- arch/arm64/kernel/irq.c | 61 +++++++++ arch/arm64/kernel/process.c | 7 ++ arch/arm64/kernel/smp.c | 222 ++++++++++++++++++--------------- arch/arm64/kernel/smp_psci.c | 54 ++++++-- arch/arm64/kernel/smp_spin_table.c | 85 ++++++++++++- arch/arm64/kernel/vmlinux.lds.S | 1 - drivers/acpi/Kconfig | 10 ++ drivers/acpi/Makefile | 1 + drivers/acpi/plat/arm/boot.c | 20 +-- drivers/acpi/sci_emu.c | 145 +++++++++++++++++++++ 16 files changed, 538 insertions(+), 150 deletions(-) create mode 100644 drivers/acpi/sci_emu.c
This reverts commit b527efad22647cce76bf555252ae1574ea364529.
Since Mark Rutland implmented cpu online/offline on ARM64, this commit should be reverted and apply Mark's patch set instead. --- arch/arm64/Kconfig | 7 ------- arch/arm64/include/asm/smp.h | 3 --- arch/arm64/kernel/smp.c | 21 --------------------- 3 files changed, 31 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b0fd1aa..db8ad10 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -183,13 +183,6 @@ config NR_CPUS default "8" if ARCH_XGENE default "4"
-config HOTPLUG_CPU - bool "Support for hot-pluggable CPUs" - depends on SMP && HOTPLUG - help - Say Y here to experiment with turning CPUs off and on. CPUs - can be controlled through /sys/devices/system/cpu. - source kernel/Kconfig.preempt
config HZ diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 95c9f58..4b8023c 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -63,9 +63,6 @@ extern struct secondary_data secondary_data; extern void secondary_holding_pen(void); extern volatile unsigned long secondary_holding_pen_release;
-extern int __cpu_disable(void); -extern void __cpu_die(unsigned int cpu); - extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index b923cfc..d2cd58c 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -261,27 +261,6 @@ static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name) return NULL; }
-#ifdef CONFIG_HOTPLUG_CPU -/* - * __cpu_disable runs on the processor to be shutdown. - */ -int __cpuinit __cpu_disable(void) -{ - pr_info("entered __cpu_disable(), assume always success\n"); - return 0; -} - -/* - * called on the thread which is asking for a CPU to be shutdown - - * waits until shutdown has completed, or it is timed out. - */ -void __cpuinit __cpu_die(unsigned int cpu) -{ - pr_info("entered __cpu_disable(), cpu %d will go away\n", cpu); - return; -} -#endif /* CONFIG_HOTPLUG_CPU */ - /* * Enumerate the possible CPU set from the device tree and build the * cpu logical map array containing MPIDR values related to logical
From: Mark Rutland mark.rutland@arm.com
For hotplug support, we're going to want a place to store operations that do more than bring CPUs online, and it makes sense to group these with our current smp_enable_ops.
This patch renames smp_enable_ops to smp_ops to make the intended use of the structure clearer. While we're at it, fix up instances of the cpu parameter to be an unsigned int, drop the init markinss and rename the *_cpu functions to cpu_* to reduce future churn when smp_operations is extended.
Signed-off-by: Mark Rutland mark.rutland@arm.com --- arch/arm64/include/asm/smp.h | 10 +++++----- arch/arm64/kernel/smp.c | 24 ++++++++++++------------ arch/arm64/kernel/smp_psci.c | 10 +++++----- arch/arm64/kernel/smp_spin_table.c | 10 +++++----- 4 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 4b8023c..90626b6 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -68,13 +68,13 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
struct device_node;
-struct smp_enable_ops { +struct smp_operations { const char *name; - int (*init_cpu)(struct device_node *, int); - int (*prepare_cpu)(int); + int (*cpu_init)(struct device_node *, unsigned int); + int (*cpu_prepare)(unsigned int); };
-extern const struct smp_enable_ops smp_spin_table_ops; -extern const struct smp_enable_ops smp_psci_ops; +extern const struct smp_operations smp_spin_table_ops; +extern const struct smp_operations smp_psci_ops;
#endif /* ifndef __ASM_SMP_H */ diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d2cd58c..3cedd3f 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -239,17 +239,17 @@ void __init smp_prepare_boot_cpu(void)
static void (*smp_cross_call)(const struct cpumask *, unsigned int);
-static const struct smp_enable_ops *enable_ops[] __initconst = { +static const struct smp_operations *supported_smp_ops[] __initconst = { &smp_spin_table_ops, &smp_psci_ops, NULL, };
-static const struct smp_enable_ops *smp_enable_ops[NR_CPUS]; +static const struct smp_operations *smp_ops[NR_CPUS];
-static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name) +static const struct smp_operations * __init smp_get_ops(const char *name) { - const struct smp_enable_ops **ops = enable_ops; + const struct smp_operations **ops = supported_smp_ops;
while (*ops) { if (!strcmp(name, (*ops)->name)) @@ -270,7 +270,7 @@ void __init smp_init_cpus(void) { const char *enable_method; struct device_node *dn = NULL; - int i, cpu = 1; + unsigned int i, cpu = 1; bool bootcpu_valid = false;
while ((dn = of_find_node_by_type(dn, "cpu"))) { @@ -349,15 +349,15 @@ void __init smp_init_cpus(void) goto next; }
- smp_enable_ops[cpu] = smp_get_enable_ops(enable_method); + smp_ops[cpu] = smp_get_ops(enable_method);
- if (!smp_enable_ops[cpu]) { + if (!smp_ops[cpu]) { pr_err("%s: invalid enable-method property: %s\n", dn->full_name, enable_method); goto next; }
- if (smp_enable_ops[cpu]->init_cpu(dn, cpu)) + if (smp_ops[cpu]->cpu_init(dn, cpu)) goto next;
pr_debug("cpu logical map 0x%llx\n", hwid); @@ -387,8 +387,8 @@ next:
void __init smp_prepare_cpus(unsigned int max_cpus) { - int cpu, err; - unsigned int ncores = num_possible_cpus(); + int err; + unsigned int cpu, ncores = num_possible_cpus();
init_cpu_topology(); store_cpu_topology(smp_processor_id()); @@ -418,10 +418,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (cpu == smp_processor_id()) continue;
- if (!smp_enable_ops[cpu]) + if (!smp_ops[cpu]) continue;
- err = smp_enable_ops[cpu]->prepare_cpu(cpu); + err = smp_ops[cpu]->cpu_prepare(cpu); if (err) continue;
diff --git a/arch/arm64/kernel/smp_psci.c b/arch/arm64/kernel/smp_psci.c index 0c53330..2f0d3dd 100644 --- a/arch/arm64/kernel/smp_psci.c +++ b/arch/arm64/kernel/smp_psci.c @@ -23,12 +23,12 @@ #include <asm/psci.h> #include <asm/smp_plat.h>
-static int __init smp_psci_init_cpu(struct device_node *dn, int cpu) +static int smp_psci_cpu_init(struct device_node *dn, unsigned int cpu) { return 0; }
-static int __init smp_psci_prepare_cpu(int cpu) +static int smp_psci_cpu_prepare(unsigned int cpu) { int err;
@@ -46,8 +46,8 @@ static int __init smp_psci_prepare_cpu(int cpu) return 0; }
-const struct smp_enable_ops smp_psci_ops __initconst = { +const struct smp_operations smp_psci_ops = { .name = "psci", - .init_cpu = smp_psci_init_cpu, - .prepare_cpu = smp_psci_prepare_cpu, + .cpu_init = smp_psci_cpu_init, + .cpu_prepare = smp_psci_cpu_prepare, }; diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c index 7c35fa6..5fecffc 100644 --- a/arch/arm64/kernel/smp_spin_table.c +++ b/arch/arm64/kernel/smp_spin_table.c @@ -24,7 +24,7 @@
static phys_addr_t cpu_release_addr[NR_CPUS];
-static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu) +static int smp_spin_table_cpu_init(struct device_node *dn, unsigned int cpu) { /* * Determine the address from which the CPU is polling. @@ -40,7 +40,7 @@ static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu) return 0; }
-static int __init smp_spin_table_prepare_cpu(int cpu) +static int smp_spin_table_cpu_prepare(unsigned int cpu) { void **release_addr;
@@ -59,8 +59,8 @@ static int __init smp_spin_table_prepare_cpu(int cpu) return 0; }
-const struct smp_enable_ops smp_spin_table_ops __initconst = { +const struct smp_operations smp_spin_table_ops = { .name = "spin-table", - .init_cpu = smp_spin_table_init_cpu, - .prepare_cpu = smp_spin_table_prepare_cpu, + .cpu_init = smp_spin_table_cpu_init, + .cpu_prepare = smp_spin_table_cpu_prepare, };
From: Mark Rutland mark.rutland@arm.com
The arm64 kernel has an internal holding pen, which is necessary for some systems where we can't bring CPUs online individually and must hold multiple CPUs in a safe area until the kernel is able to handle them. The current SMP infrastructure for arm64 is closely coupled to this holding pen, and alternative boot methods must launch CPUs into the pen, where they sit before they are launched into the kernel proper.
With PSCI (and possibly other future boot methods), we can bring CPUs online individually, and need not perform the secondary_holding_pen dance. Instead, this patch factors the holding pen management code out to the spin-table boot method code, as it is the only boot method requiring the pen.
A new entry point for secondaries, secondary_entry is added for other boot methods to use, which bypasses the holding pen and its associated overhead when bringing CPUs online. The smp.pen.text section is also removed, as the pen can live in head.text without problem.
The smp_operations structure is extended with two new functions, cpu_boot and cpu_postboot, for bringing a cpu into the kernel and performing any post-boot cleanup required by a bootmethod (e.g. resetting the secondary_holding_pen_release to INVALID_HWID). Documentation is added for smp_operations.
Signed-off-by: Mark Rutland mark.rutland@arm.com Cc: Santosh Shilimkar santosh.shilimkar@ti.com --- arch/arm64/include/asm/smp.h | 19 ++++++++- arch/arm64/kernel/head.S | 12 +++++- arch/arm64/kernel/smp.c | 67 +++----------------------------- arch/arm64/kernel/smp_psci.c | 16 ++++---- arch/arm64/kernel/smp_spin_table.c | 75 ++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/vmlinux.lds.S | 1 - 6 files changed, 117 insertions(+), 73 deletions(-)
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 90626b6..831090a 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -60,18 +60,33 @@ struct secondary_data { void *stack; }; extern struct secondary_data secondary_data; -extern void secondary_holding_pen(void); -extern volatile unsigned long secondary_holding_pen_release; +extern void secondary_entry(void);
extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
struct device_node;
+/** + * struct smp_operations - Callback operations for hotplugging CPUs. + * + * @name: Name of the property as appears in a devicetree cpu node's + * enable-method property. + * @cpu_init: Reads any data necessary for a specific enable-method form the + * devicetree, for a given cpu node and proposed logical id. + * @cpu_prepare: Early one-time preparation step for a cpu. If there is a + * mechanism for doing so, tests whether it is possible to boot + * the given CPU. + * @cpu_boot: Boots a cpu into the kernel. + * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary + * synchronisation. Called from the cpu being booted. + */ struct smp_operations { const char *name; int (*cpu_init)(struct device_node *, unsigned int); int (*cpu_prepare)(unsigned int); + int (*cpu_boot)(unsigned int); + void (*cpu_postboot)(void); };
extern const struct smp_operations smp_spin_table_ops; diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 53dcae4..3532ca6 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -217,7 +217,6 @@ ENTRY(__boot_cpu_mode) .quad PAGE_OFFSET
#ifdef CONFIG_SMP - .pushsection .smp.pen.text, "ax" .align 3 1: .quad . .quad secondary_holding_pen_release @@ -242,7 +241,16 @@ pen: ldr x4, [x3] wfe b pen ENDPROC(secondary_holding_pen) - .popsection + + /* + * Secondary entry point that jumps straight into the kernel. Only to + * be used where CPUs are brought online dynamically by the kernel. + */ +ENTRY(secondary_entry) + bl __calc_phys_offset // x2=phys offset + bl el2_setup // Drop to EL1 + b secondary_startup +ENDPROC(secondary_entry)
ENTRY(secondary_startup) /* diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 3cedd3f..f633252 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -55,7 +55,6 @@ * where to place its SVC stack */ struct secondary_data secondary_data; -volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
enum ipi_msg_type { IPI_RESCHEDULE, @@ -64,22 +63,7 @@ enum ipi_msg_type { IPI_CPU_STOP, };
-static DEFINE_RAW_SPINLOCK(boot_lock); - -/* - * Write secondary_holding_pen_release in a way that is guaranteed to be - * visible to all observers, irrespective of whether they're taking part - * in coherency or not. This is necessary for the hotplug code to work - * reliably. - */ -static void write_pen_release(u64 val) -{ - void *start = (void *)&secondary_holding_pen_release; - unsigned long size = sizeof(secondary_holding_pen_release); - - secondary_holding_pen_release = val; - __flush_dcache_area(start, size); -} +static const struct smp_operations *smp_ops[NR_CPUS];
/* * Boot a secondary CPU, and assign it the specified idle task. @@ -87,38 +71,10 @@ static void write_pen_release(u64 val) */ static int boot_secondary(unsigned int cpu, struct task_struct *idle) { - unsigned long timeout; - - /* - * Set synchronisation state between this boot processor - * and the secondary one - */ - raw_spin_lock(&boot_lock); - - /* - * Update the pen release flag. - */ - write_pen_release(cpu_logical_map(cpu)); - - /* - * Send an event, causing the secondaries to read pen_release. - */ - sev(); - - timeout = jiffies + (1 * HZ); - while (time_before(jiffies, timeout)) { - if (secondary_holding_pen_release == INVALID_HWID) - break; - udelay(10); - } - - /* - * Now the secondary core is starting up let it run its - * calibrations, then wait for it to finish - */ - raw_spin_unlock(&boot_lock); + if (smp_ops[cpu]->cpu_boot) + return smp_ops[cpu]->cpu_boot(cpu);
- return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0; + return -EOPNOTSUPP; }
static DECLARE_COMPLETION(cpu_running); @@ -188,17 +144,8 @@ asmlinkage void secondary_start_kernel(void) preempt_disable(); trace_hardirqs_off();
- /* - * Let the primary processor know we're out of the - * pen, then head off into the C entry point - */ - write_pen_release(INVALID_HWID); - - /* - * Synchronise with the boot thread. - */ - raw_spin_lock(&boot_lock); - raw_spin_unlock(&boot_lock); + if (smp_ops[cpu]->cpu_postboot) + smp_ops[cpu]->cpu_postboot();
store_cpu_topology(cpu);
@@ -245,8 +192,6 @@ static const struct smp_operations *supported_smp_ops[] __initconst = { NULL, };
-static const struct smp_operations *smp_ops[NR_CPUS]; - static const struct smp_operations * __init smp_get_ops(const char *name) { const struct smp_operations **ops = supported_smp_ops; diff --git a/arch/arm64/kernel/smp_psci.c b/arch/arm64/kernel/smp_psci.c index 2f0d3dd..20499bc 100644 --- a/arch/arm64/kernel/smp_psci.c +++ b/arch/arm64/kernel/smp_psci.c @@ -30,24 +30,26 @@ static int smp_psci_cpu_init(struct device_node *dn, unsigned int cpu)
static int smp_psci_cpu_prepare(unsigned int cpu) { - int err; - if (!psci_ops.cpu_on) { pr_err("psci: no cpu_on method, not booting CPU%d\n", cpu); return -ENODEV; }
- err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_holding_pen)); - if (err) { + return 0; +} + +static int smp_psci_cpu_boot(unsigned int cpu) +{ + int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry)); + if (err) pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err); - return err; - }
- return 0; + return err; }
const struct smp_operations smp_psci_ops = { .name = "psci", .cpu_init = smp_psci_cpu_init, .cpu_prepare = smp_psci_cpu_prepare, + .cpu_boot = smp_psci_cpu_boot, }; diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c index 5fecffc..87af6bb 100644 --- a/arch/arm64/kernel/smp_spin_table.c +++ b/arch/arm64/kernel/smp_spin_table.c @@ -16,13 +16,36 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */
+#include <linux/delay.h> #include <linux/init.h> #include <linux/of.h> #include <linux/smp.h>
#include <asm/cacheflush.h> +#include <asm/cputype.h> +#include <asm/smp_plat.h> + +extern void secondary_holding_pen(void); +volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
static phys_addr_t cpu_release_addr[NR_CPUS]; +static DEFINE_RAW_SPINLOCK(boot_lock); + +/* + * Write secondary_holding_pen_release in a way that is guaranteed to be + * visible to all observers, irrespective of whether they're taking part + * in coherency or not. This is necessary for the hotplug code to work + * reliably. + */ +static void write_pen_release(u64 val) +{ + void *start = (void *)&secondary_holding_pen_release; + unsigned long size = sizeof(secondary_holding_pen_release); + + secondary_holding_pen_release = val; + __flush_dcache_area(start, size); +} +
static int smp_spin_table_cpu_init(struct device_node *dn, unsigned int cpu) { @@ -59,8 +82,60 @@ static int smp_spin_table_cpu_prepare(unsigned int cpu) return 0; }
+static int smp_spin_table_cpu_boot(unsigned int cpu) +{ + unsigned long timeout; + + /* + * Set synchronisation state between this boot processor + * and the secondary one + */ + raw_spin_lock(&boot_lock); + + /* + * Update the pen release flag. + */ + write_pen_release(cpu_logical_map(cpu)); + + /* + * Send an event, causing the secondaries to read pen_release. + */ + sev(); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + if (secondary_holding_pen_release == INVALID_HWID) + break; + udelay(10); + } + + /* + * Now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + raw_spin_unlock(&boot_lock); + + return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0; +} + +void smp_spin_table_cpu_postboot(void) +{ + /* + * Let the primary processor know we're out of the pen. + */ + write_pen_release(INVALID_HWID); + + /* + * Synchronise with the boot thread. + */ + raw_spin_lock(&boot_lock); + raw_spin_unlock(&boot_lock); +} + const struct smp_operations smp_spin_table_ops = { .name = "spin-table", .cpu_init = smp_spin_table_cpu_init, .cpu_prepare = smp_spin_table_cpu_prepare, + .cpu_boot = smp_spin_table_cpu_boot, + .cpu_postboot = smp_spin_table_cpu_postboot, }; diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index f5e5574..d8ca8d9 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -54,7 +54,6 @@ SECTIONS } .text : { /* Real text segment */ _stext = .; /* Text and read-only data */ - *(.smp.pen.text) __exception_text_start = .; *(.exception.text) __exception_text_end = .;
From: Mark Rutland mark.rutland@arm.com
With the advent of CPU_HOTPLUG, the enable-method property for CPU0 may tells us something useful (i.e. how to hotplug it back on), so we must read it along with all the enable-method for all the other CPUs.
This patch ensures that CPU0's enable-method property is read.
Signed-off-by: Mark Rutland mark.rutland@arm.com --- arch/arm64/kernel/smp.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index f633252..a30ac03 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -257,6 +257,8 @@ void __init smp_init_cpus(void) } }
+ enable_method = of_get_property(dn, "enable-method", NULL); + /* * The numbering scheme requires that the boot CPU * must be assigned logical id 0. Record it so that @@ -272,11 +274,12 @@ void __init smp_init_cpus(void)
bootcpu_valid = true;
+ if (enable_method) + smp_ops[0] = smp_get_ops(enable_method); + /* - * cpu_logical_map has already been - * initialized and the boot cpu doesn't need - * the enable-method so continue without - * incrementing cpu. + * cpu_logical_map has already been initialized so + * continue without incrementing cpu. */ continue; } @@ -284,10 +287,6 @@ void __init smp_init_cpus(void) if (cpu >= NR_CPUS) goto next;
- /* - * We currently support only the "spin-table" enable-method. - */ - enable_method = of_get_property(dn, "enable-method", NULL); if (!enable_method) { pr_err("%s: missing enable-method property\n", dn->full_name);
From: Mark Rutland mark.rutland@arm.com
This patch adds the basic infrastructure necessary to support CPU_HOTPLUG on arm64, based on the arm implementation. Actual hotplug support will depend on an implementation's smp_operations (e.g. PSCI).
Signed-off-by: Mark Rutland mark.rutland@arm.com --- arch/arm64/Kconfig | 7 +++ arch/arm64/include/asm/irq.h | 1 + arch/arm64/include/asm/smp.h | 14 ++++++ arch/arm64/kernel/cputable.c | 2 +- arch/arm64/kernel/irq.c | 61 ++++++++++++++++++++++++++ arch/arm64/kernel/process.c | 7 +++ arch/arm64/kernel/smp.c | 97 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 188 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index db8ad10..e285ba1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -183,6 +183,13 @@ config NR_CPUS default "8" if ARCH_XGENE default "4"
+config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs" + depends on SMP + help + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu. + source kernel/Kconfig.preempt
config HZ diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 0332fc0..e1f7ecd 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -4,6 +4,7 @@ #include <asm-generic/irq.h>
extern void (*handle_arch_irq)(struct pt_regs *); +extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
#endif diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index 831090a..d2ef02e 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -67,6 +67,11 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
struct device_node;
+extern int __cpu_disable(void); + +extern void __cpu_die(unsigned int cpu); +extern void cpu_die(void); + /** * struct smp_operations - Callback operations for hotplugging CPUs. * @@ -80,6 +85,11 @@ struct device_node; * @cpu_boot: Boots a cpu into the kernel. * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary * synchronisation. Called from the cpu being booted. + * @cpu_disable: Prepares a cpu to die. May fail for some mechanism-specific + * reason, which will cause the hot unplug to be aborted. Called + * from the cpu to be killed. + * @cpu_die: Makes the a leave the kernel. Must not fail. Called from the + * cpu being killed. */ struct smp_operations { const char *name; @@ -87,6 +97,10 @@ struct smp_operations { int (*cpu_prepare)(unsigned int); int (*cpu_boot)(unsigned int); void (*cpu_postboot)(void); +#ifdef CONFIG_HOTPLUG_CPU + int (*cpu_disable)(unsigned int cpu); + void (*cpu_die)(unsigned int cpu); +#endif };
extern const struct smp_operations smp_spin_table_ops; diff --git a/arch/arm64/kernel/cputable.c b/arch/arm64/kernel/cputable.c index 63cfc4a..fd3993c 100644 --- a/arch/arm64/kernel/cputable.c +++ b/arch/arm64/kernel/cputable.c @@ -22,7 +22,7 @@
extern unsigned long __cpu_setup(void);
-struct cpu_info __initdata cpu_table[] = { +struct cpu_info cpu_table[] = { { .cpu_id_val = 0x000f0000, .cpu_id_mask = 0x000f0000, diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index ecb3354..473e5db 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -81,3 +81,64 @@ void __init init_IRQ(void) if (!handle_arch_irq) panic("No interrupt controller found."); } + +#ifdef CONFIG_HOTPLUG_CPU +static bool migrate_one_irq(struct irq_desc *desc) +{ + struct irq_data *d = irq_desc_get_irq_data(desc); + const struct cpumask *affinity = d->affinity; + struct irq_chip *c; + bool ret = false; + + /* + * If this is a per-CPU interrupt, or the affinity does not + * include this CPU, then we have nothing to do. + */ + if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) + return false; + + if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { + affinity = cpu_online_mask; + ret = true; + } + + c = irq_data_get_irq_chip(d); + if (!c->irq_set_affinity) + pr_debug("IRQ%u: unable to set affinity\n", d->irq); + else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret) + cpumask_copy(d->affinity, affinity); + + return ret; +} + +/* + * The current CPU has been marked offline. Migrate IRQs off this CPU. + * If the affinity settings do not allow other CPUs, force them onto any + * available CPU. + * + * Note: we must iterate over all IRQs, whether they have an attached + * action structure or not, as we need to get chained interrupts too. + */ +void migrate_irqs(void) +{ + unsigned int i; + struct irq_desc *desc; + unsigned long flags; + + local_irq_save(flags); + + for_each_irq_desc(i, desc) { + bool affinity_broken; + + raw_spin_lock(&desc->lock); + affinity_broken = migrate_one_irq(desc); + raw_spin_unlock(&desc->lock); + + if (affinity_broken) + pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n", + i, smp_processor_id()); + } + + local_irq_restore(flags); +} +#endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 2a7a649..b05026c 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -102,6 +102,13 @@ void arch_cpu_idle(void) local_irq_enable(); }
+#ifdef CONFIG_HOTPLUG_CPU +void arch_cpu_idle_dead(void) +{ + cpu_die(); +} +#endif + void machine_shutdown(void) { #ifdef CONFIG_SMP diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index a30ac03..f074292 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -171,6 +171,103 @@ asmlinkage void secondary_start_kernel(void) cpu_startup_entry(CPUHP_ONLINE); }
+#ifdef CONFIG_HOTPLUG_CPU +static int op_cpu_disable(unsigned int cpu) +{ + /* + * If we don't have a cpu_die method, abort before we reach the point + * of no return. CPU0 may not have an smp_ops, so test for it. + */ + if (!smp_ops[cpu] || !smp_ops[cpu]->cpu_die) + return -EOPNOTSUPP; + + /* + * We may need to abort a hot unplug for some other mechanism-specific + * reason. + */ + if (smp_ops[cpu]->cpu_disable) + return smp_ops[cpu]->cpu_disable(cpu); + + return 0; +} + +/* + * __cpu_disable runs on the processor to be shutdown. + */ +int __cpu_disable(void) +{ + unsigned int cpu = smp_processor_id(); + int ret; + + ret = op_cpu_disable(cpu); + if (ret) + return ret; + + /* + * Take this CPU offline. Once we clear this, we can't return, + * and we must not schedule until we're ready to give up the cpu. + */ + set_cpu_online(cpu, false); + + /* + * OK - migrate IRQs away from this CPU + */ + migrate_irqs(); + + /* + * Remove this CPU from the vm mask set of all processes. + */ + clear_tasks_mm_cpumask(cpu); + + return 0; +} + +static DECLARE_COMPLETION(cpu_died); + +/* + * called on the thread which is asking for a CPU to be shutdown - + * waits until shutdown has completed, or it is timed out. + */ +void __cpu_die(unsigned int cpu) +{ + if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { + pr_crit("CPU%u: cpu didn't die\n", cpu); + return; + } + pr_notice("CPU%u: shutdown\n", cpu); +} + +/* + * Called from the idle thread for the CPU which has been shutdown. + * + * Note that we disable IRQs here, but do not re-enable them + * before returning to the caller. This is also the behaviour + * of the other hotplug-cpu capable cores, so presumably coming + * out of idle fixes this. + */ +void __ref cpu_die(void) +{ + unsigned int cpu = smp_processor_id(); + + idle_task_exit(); + + local_irq_disable(); + mb(); + + /* Tell __cpu_die() that this CPU is now safe to dispose of */ + complete(&cpu_died); + + /* + * Actually shutdown the CPU. This must never fail. The specific hotplug + * mechanism must perform all required cache maintenance to ensure that + * no dirty lines are lost in the process of shutting down the CPU. + */ + smp_ops[cpu]->cpu_die(cpu); + + BUG(); +} +#endif + void __init smp_cpus_done(unsigned int max_cpus) { unsigned long bogosum = loops_per_jiffy * num_online_cpus();
From: Mark Rutland mark.rutland@arm.com
This patch adds support for using PSCI CPU_OFF calls for CPU hotplug. With this code it is possible to hot unplug CPUs with "psci" as their boot-method, as long as there's an appropriate cpu_off function id specified in the psci node.
Signed-off-by: Mark Rutland mark.rutland@arm.com --- arch/arm64/kernel/smp_psci.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/arch/arm64/kernel/smp_psci.c b/arch/arm64/kernel/smp_psci.c index 20499bc..e9e5890 100644 --- a/arch/arm64/kernel/smp_psci.c +++ b/arch/arm64/kernel/smp_psci.c @@ -47,9 +47,39 @@ static int smp_psci_cpu_boot(unsigned int cpu) return err; }
+#ifdef CONFIG_HOTPLUG_CPU +static int smp_psci_cpu_disable(unsigned int cpu) +{ + /* Fail early if we don't have CPU_OFF support */ + if (!psci_ops.cpu_off) + return -EOPNOTSUPP; + return 0; +} + +static void smp_psci_cpu_die(unsigned int cpu) +{ + int ret; + /* + * There are no known implementations of PSCI actually using the + * power state field, pass a sensible default for now. + */ + struct psci_power_state state = { + .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, + }; + + ret = psci_ops.cpu_off(state); + + pr_crit("psci: unable to power off CPU%u (%d)\n", cpu, ret); +} +#endif + const struct smp_operations smp_psci_ops = { .name = "psci", .cpu_init = smp_psci_cpu_init, .cpu_prepare = smp_psci_cpu_prepare, .cpu_boot = smp_psci_cpu_boot, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = smp_psci_cpu_disable, + .cpu_die = smp_psci_cpu_die, +#endif };
From: Mark Rutland mark.rutland@arm.com
On Thu, Jul 11, 2013 at 04:10:51PM +0100, Hanjun Guo wrote:
Hi Mark,
Hi Hanjun,
I tested this patch set on the armv8 foundation model, it's panic.
I seems that we need to do something more, I'll also checkout what's going on here.
Thanks Hanjun
dump formation: root@genericarmv8:/sys/devices/system/cpu/cpu3# echo 0 > online CPU3: Booted secondary processor CPU3: shutdown BUG: failure at kernel/time/clockevents.c:284/clockevents_register_device()! Kernel panic - not syncing: BUG! CPU: 3 PID: 0 Comm: swapper/3 Not tainted 3.10.0+ #2 Call trace: [<ffffffc0000873e0>] dump_backtrace+0x0/0x12c [<ffffffc000087520>] show_stack+0x14/0x1c [<ffffffc0003f2e7c>] dump_stack+0x20/0x28 [<ffffffc0003efd24>] panic+0xe8/0x214 [<ffffffc0000d049c>] clockevents_set_mode+0x0/0x6c [<ffffffc0000d074c>] clockevents_config_and_register+0x24/0x30 [<ffffffc0003ef840>] arch_timer_setup+0xd8/0x140 [<ffffffc0003ef8f0>] arch_timer_cpu_notify+0x48/0xc8 [<ffffffc0000b83e4>] notifier_call_chain+0x48/0x88 [<ffffffc0000b8500>] __raw_notifier_call_chain+0xc/0x14 [<ffffffc0000973f0>] __cpu_notify+0x30/0x58 [<ffffffc00009742c>] cpu_notify+0x14/0x1c [<ffffffc0003ed46c>] notify_cpu_starting+0x14/0x1c [<ffffffc0003ece74>] secondary_start_kernel+0xc0/0xf4
That looks suspicious. It looks like the CPU didn't actually die and jumped immediately to secondary_start_kernel. At a guess, did you update your dts with a psci node and cpu enable-methods?
I can see the code's broken if you try hotplug with spin-table, because cpu_disable and cpu_die are both NULL, and the sanity checking doesn't attempt to deal with this case, so the cpu will end up getting into cpu_die, won't call anything, and jump straight back into the kernel. I'll fix up the op_cpu_disable checks to cover this.
The other possibility is that you're using PSCI but your function id for cpu_off is wrong, and thus the psci cpu_off call fails. Did you update your dts for PSCI? Below is a patch to do so.
Thanks, Mark. --- arch/arm64/boot/dts/foundation-v8.dts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/foundation-v8.dts index 84fcc50..335a88f 100644 --- a/arch/arm64/boot/dts/foundation-v8.dts +++ b/arch/arm64/boot/dts/foundation-v8.dts @@ -22,6 +22,13 @@ serial3 = &v2m_serial3; };
+ psci { + compatible = "arm,psci"; + method = "smc"; + cpu_off = <0x84000001>; + cpu_on = <0x84000002>; + }; + cpus { #address-cells = <2>; #size-cells = <0>; @@ -30,29 +37,25 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; }; cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x1>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; }; cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x2>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; }; cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x3>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; + enable-method = "psci"; }; };
From: Ashok Raj ashok.raj@intel.com
This patch is for hotplug test only.
Emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful for testing ACPI based hot-plug on systems that don't have the necessary firmware support.
Enable CONFIG_ACPI_SCI_EMULATE on kernel compile.
Now you will notice /sys/kernel/debug/acpi/sci_notify when new kernel is booted.
echo "_SB.PCIB 1" > /sys/kernel/debug/acpi/sci_notify to trigger a hot-add of root bus that is corresponding to PCIB.
echo "_SB.PCIB 3" > /sys/kernel/debug/acpi/sci_notify to trigger a hot-remove of root bus that is corresponding to PCIB.
-v2: Update to current upstream, and remove not related stuff. -v3: According to Len's request, update it to use debugfs. - Yinghai Lu
Signed-off-by: Yinghai Lu yinghai@kernel.org Cc: Len Brown lenb@kernel.org Cc: linux-acpi@vger.kernel.org --- drivers/acpi/Kconfig | 10 ++++ drivers/acpi/Makefile | 1 + drivers/acpi/sci_emu.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 drivers/acpi/sci_emu.c
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 85f774a..0d7f6eb 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -294,6 +294,16 @@ config ACPI_BLACKLIST_YEAR Enter 0 to disable this mechanism and allow ACPI to run by default no matter what the year. (default)
+config ACPI_SCI_EMULATE + bool "ACPI SCI Event Emulation Support" + depends on DEBUG_FS + default n + help + This will enable your system to emulate sci hotplug event + notification through proc file system. For example user needs to + echo "XXX 0" > /sys/kernel/debug/acpi/sci_notify (where, XXX is + a target ACPI device object name present under _SB scope). + config ACPI_DEBUG bool "Debug Statements" default n diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index fc0949f..6412cd1 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -32,6 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # ACPI Bus and Device Drivers # acpi-y += bus.o glue.o +acpi-$(CONFIG_ACPI_SCI_EMULATE) += sci_emu.o acpi-y += scan.o acpi-y += resource.o acpi-y += acpi_processor.o diff --git a/drivers/acpi/sci_emu.c b/drivers/acpi/sci_emu.c new file mode 100644 index 0000000..2f13ca1 --- /dev/null +++ b/drivers/acpi/sci_emu.c @@ -0,0 +1,145 @@ +/* + * Code to emulate SCI interrupt for Hotplug node insertion/removal + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <acpi/acpi_drivers.h> + +#include "internal.h" + +#include "acpica/accommon.h" +#include "acpica/acnamesp.h" +#include "acpica/acevents.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME("sci_emu"); +MODULE_LICENSE("GPL"); + +static struct dentry *sci_notify_dentry; + +static void sci_notify_client(char *acpi_name, u32 event) +{ + struct acpi_namespace_node *node; + acpi_status status, status1; + acpi_handle hlsb, hsb; + union acpi_operand_object *obj_desc; + + status = acpi_get_handle(NULL, "\_SB", &hsb); + status1 = acpi_get_handle(hsb, acpi_name, &hlsb); + if (ACPI_FAILURE(status) || ACPI_FAILURE(status1)) { + pr_err(PREFIX + "acpi getting handle to <\_SB.%s> failed inside notify_client\n", + acpi_name); + return; + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + pr_err(PREFIX "Acquiring acpi namespace mutext failed\n"); + return; + } + + node = acpi_ns_validate_handle(hlsb); + if (!node) { + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + pr_err(PREFIX "Mapping handle to node failed\n"); + return; + } + + /* + * Check for internal object and make sure there is a handler + * registered for this object + */ + obj_desc = acpi_ns_get_attached_object(node); + if (obj_desc) { + if (obj_desc->common_notify.notify_list[0]) { + /* + * Release the lock and queue the item for later + * exectuion + */ + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + status = acpi_ev_queue_notify_request(node, event); + if (ACPI_FAILURE(status)) + pr_err(PREFIX "acpi_ev_queue_notify_request failed\n"); + else + pr_info(PREFIX "Notify event is queued\n"); + return; + } + } else { + pr_info(PREFIX "Notify handler not registered for this device\n"); + } + + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return; +} + +static ssize_t sci_notify_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + u32 event; + char *name1 = NULL; + char *name2 = NULL; + const char *delim = " "; + char *temp_buf = NULL; + char *temp_buf_addr = NULL; + + temp_buf = kmalloc(count+1, GFP_ATOMIC); + if (!temp_buf) { + pr_warn(PREFIX "sci_notify_wire: Memory allocation failed\n"); + return count; + } + temp_buf[count] = '\0'; + temp_buf_addr = temp_buf; + if (copy_from_user(temp_buf, user_buf, count)) + goto out; + + name1 = strsep(&temp_buf, delim); + name2 = strsep(&temp_buf, delim); + + if (name1 && name2) { + ssize_t ret; + unsigned long val; + + ret = kstrtoul(name2, 10, &val); + if (ret) { + pr_warn(PREFIX "unknown event\n"); + goto out; + } + + event = (u32)val; + } else { + pr_warn(PREFIX "unknown device\n"); + goto out; + } + + pr_info(PREFIX "ACPI device name is <%s>, event code is <%d>\n", + name1, event); + + sci_notify_client(name1, event); + +out: + kfree(temp_buf_addr); + return count; +} + +static const struct file_operations sci_notify_fops = { + .write = sci_notify_write, +}; + +static int __init acpi_sci_notify_init(void) +{ + if (acpi_debugfs_dir == NULL) + return -ENOENT; + + sci_notify_dentry = debugfs_create_file("sci_notify", S_IWUSR, + acpi_debugfs_dir, NULL, &sci_notify_fops); + if (sci_notify_dentry == NULL) + return -ENODEV; + + return 0; +} + +device_initcall(acpi_sci_notify_init);
__cpuinit is gone in kernel now, remove them.
__init belongs after the return type on functions, not before, correct them too.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/plat/arm/boot.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 8600cd0..928f6c9 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -147,7 +147,7 @@ static int __init acpi_parse_madt(struct acpi_table_header *table) }
/* Local APIC = GIC cpu interface on ARM */ -static void __cpuinit acpi_register_lapic(int id, u8 enabled) +static void acpi_register_lapic(int id, u8 enabled) { int cpu;
@@ -365,7 +365,7 @@ early_param("possible_cpus", _setup_possible_cpus); * We do this because additional CPUs waste a lot of memory. * -AK */ -__init void prefill_possible_map(void) +void __init prefill_possible_map(void) { int i; int possible, disabled_cpus; @@ -405,7 +405,7 @@ __init void prefill_possible_map(void) #ifdef CONFIG_ACPI_HOTPLUG_CPU #include <acpi/processor.h>
-static void __cpuinit acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) { #ifdef CONFIG_ACPI_NUMA int nid; @@ -418,7 +418,7 @@ static void __cpuinit acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) #endif }
-static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) +static int _acpi_map_lsapic(acpi_handle handle, int *pcpu) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; @@ -582,7 +582,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table) * hpet_insert_resource inserts the HPET resources used into the resource * tree. */ -static __init int hpet_insert_resource(void) +static int __init hpet_insert_resource(void) { if (!hpet_res) return 1;
'struct acpi_madt_local_apic' should be 'struct acpi_madt_generic_interrupt' instead on ARM, this will lead to cpu hot add failure because of the wrong value we used.
Tested on ARMv8 foudation model and the cpu can be hot add in ACPI way.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/acpi/plat/arm/boot.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 928f6c9..4891940 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -422,7 +422,7 @@ static int _acpi_map_lsapic(acpi_handle handle, int *pcpu) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_madt_local_apic *lapic; + struct acpi_madt_generic_interrupt *lapic; cpumask_var_t tmp_map, new_map; u8 physid; int cpu; @@ -441,15 +441,15 @@ static int _acpi_map_lsapic(acpi_handle handle, int *pcpu) return -EINVAL; }
- lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; + lapic = (struct acpi_madt_generic_interrupt *)obj->buffer.pointer;
- if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || - !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { + if (lapic->header.type != ACPI_MADT_TYPE_GENERIC_INTERRUPT || + !(lapic->flags & ACPI_MADT_ENABLED)) { kfree(buffer.pointer); return -EINVAL; }
- physid = lapic->id; + physid = lapic->gic_id;
kfree(buffer.pointer); buffer.length = ACPI_ALLOCATE_BUFFER;
Hi Hanjun,
When 3.12-rc1 is released I think we shall have to do a major rebase of your patches then?
Would it be best to leave this series until we rebase on the 3.12-rc1 LLCT tree then you can guide me through which patches to drop in the rebase?
Graeme
On Mon, Sep 02, 2013 at 07:49:02PM +0800, Hanjun Guo wrote:
This patch set is the kernel part of code for cpu hotplug.
I got a patch in upstream but not accepted by mainline, this patch emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful for testing ACPI based hot-plug on systems that don't have the necessary firmware support. With this patch, I can test the hot-add and hot-remove repeatly.
This patch set is intended to close the cpu hotplug related cards in JIRA, just for review purpose, *should not* pushed to our linaro acpi.
I have created an acpi-hotplug-next branch in our git tree for these patches.
This patch set includes 3 parts, the forst part is the kernel code, and the second is the ASL code fix, the third part is the boot wrapper.
Hanjun Guo (4): Revert "ARM64 / CPU hot-plug: Skeleton logic cpu online/offline for cpu hot-plug" ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing arm / ACPI: Remove __cpuinit and fix __init attribute location arm: fix cpu hot add failure
Mark Rutland (6): arm64: reorganise smp_enable_ops arm64: factor out spin-table boot method arm64: read enable-method for CPU0 arm64: add CPU_HOTPLUG infrastructure arm64: add PSCI CPU_OFF-based hotplug support HACK: arm64: dts: foundation: add PSCI data
arch/arm64/Kconfig | 2 +- arch/arm64/boot/dts/foundation-v8.dts | 19 +-- arch/arm64/include/asm/irq.h | 1 + arch/arm64/include/asm/smp.h | 46 +++++-- arch/arm64/kernel/cputable.c | 2 +- arch/arm64/kernel/head.S | 12 +- arch/arm64/kernel/irq.c | 61 +++++++++ arch/arm64/kernel/process.c | 7 ++ arch/arm64/kernel/smp.c | 222 ++++++++++++++++++--------------- arch/arm64/kernel/smp_psci.c | 54 ++++++-- arch/arm64/kernel/smp_spin_table.c | 85 ++++++++++++- arch/arm64/kernel/vmlinux.lds.S | 1 - drivers/acpi/Kconfig | 10 ++ drivers/acpi/Makefile | 1 + drivers/acpi/plat/arm/boot.c | 20 +-- drivers/acpi/sci_emu.c | 145 +++++++++++++++++++++ 16 files changed, 538 insertions(+), 150 deletions(-) create mode 100644 drivers/acpi/sci_emu.c
-- 1.7.9.5
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
Hi Graeme,
I think this patch set can be rebased until 3.13-rc1 is released, because cpu online/offline patch from Mark Rutland will not merged in 3.12, and likely be merged into 3.13, so if we do this work on 3.12, we have to do that again when 3.13-rc1 released, that doesn't make sense.
Thanks Hanjun
On 2013-9-5 17:08, Graeme Gregory wrote:
Hi Hanjun,
When 3.12-rc1 is released I think we shall have to do a major rebase of your patches then?
Would it be best to leave this series until we rebase on the 3.12-rc1 LLCT tree then you can guide me through which patches to drop in the rebase?
Graeme
On Mon, Sep 02, 2013 at 07:49:02PM +0800, Hanjun Guo wrote:
This patch set is the kernel part of code for cpu hotplug.
I got a patch in upstream but not accepted by mainline, this patch emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful for testing ACPI based hot-plug on systems that don't have the necessary firmware support. With this patch, I can test the hot-add and hot-remove repeatly.
This patch set is intended to close the cpu hotplug related cards in JIRA, just for review purpose, *should not* pushed to our linaro acpi.
I have created an acpi-hotplug-next branch in our git tree for these patches.
This patch set includes 3 parts, the forst part is the kernel code, and the second is the ASL code fix, the third part is the boot wrapper.
Hanjun Guo (4): Revert "ARM64 / CPU hot-plug: Skeleton logic cpu online/offline for cpu hot-plug" ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing arm / ACPI: Remove __cpuinit and fix __init attribute location arm: fix cpu hot add failure
Mark Rutland (6): arm64: reorganise smp_enable_ops arm64: factor out spin-table boot method arm64: read enable-method for CPU0 arm64: add CPU_HOTPLUG infrastructure arm64: add PSCI CPU_OFF-based hotplug support HACK: arm64: dts: foundation: add PSCI data
arch/arm64/Kconfig | 2 +- arch/arm64/boot/dts/foundation-v8.dts | 19 +-- arch/arm64/include/asm/irq.h | 1 + arch/arm64/include/asm/smp.h | 46 +++++-- arch/arm64/kernel/cputable.c | 2 +- arch/arm64/kernel/head.S | 12 +- arch/arm64/kernel/irq.c | 61 +++++++++ arch/arm64/kernel/process.c | 7 ++ arch/arm64/kernel/smp.c | 222 ++++++++++++++++++--------------- arch/arm64/kernel/smp_psci.c | 54 ++++++-- arch/arm64/kernel/smp_spin_table.c | 85 ++++++++++++- arch/arm64/kernel/vmlinux.lds.S | 1 - drivers/acpi/Kconfig | 10 ++ drivers/acpi/Makefile | 1 + drivers/acpi/plat/arm/boot.c | 20 +-- drivers/acpi/sci_emu.c | 145 +++++++++++++++++++++ 16 files changed, 538 insertions(+), 150 deletions(-) create mode 100644 drivers/acpi/sci_emu.c
-- 1.7.9.5
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
Hi Hanjun,
Thanks for explanation, patch series added to acpi tree.
Thanks
G
On Thu, Sep 05, 2013 at 05:26:58PM +0800, Hanjun Guo wrote:
Hi Graeme,
I think this patch set can be rebased until 3.13-rc1 is released, because cpu online/offline patch from Mark Rutland will not merged in 3.12, and likely be merged into 3.13, so if we do this work on 3.12, we have to do that again when 3.13-rc1 released, that doesn't make sense.
Thanks Hanjun
On 2013-9-5 17:08, Graeme Gregory wrote:
Hi Hanjun,
When 3.12-rc1 is released I think we shall have to do a major rebase of your patches then?
Would it be best to leave this series until we rebase on the 3.12-rc1 LLCT tree then you can guide me through which patches to drop in the rebase?
Graeme
On Mon, Sep 02, 2013 at 07:49:02PM +0800, Hanjun Guo wrote:
This patch set is the kernel part of code for cpu hotplug.
I got a patch in upstream but not accepted by mainline, this patch emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful for testing ACPI based hot-plug on systems that don't have the necessary firmware support. With this patch, I can test the hot-add and hot-remove repeatly.
This patch set is intended to close the cpu hotplug related cards in JIRA, just for review purpose, *should not* pushed to our linaro acpi.
I have created an acpi-hotplug-next branch in our git tree for these patches.
This patch set includes 3 parts, the forst part is the kernel code, and the second is the ASL code fix, the third part is the boot wrapper.
Hanjun Guo (4): Revert "ARM64 / CPU hot-plug: Skeleton logic cpu online/offline for cpu hot-plug" ACPI: Enable SCI_EMULATE to manually simulate physical hotplug testing arm / ACPI: Remove __cpuinit and fix __init attribute location arm: fix cpu hot add failure
Mark Rutland (6): arm64: reorganise smp_enable_ops arm64: factor out spin-table boot method arm64: read enable-method for CPU0 arm64: add CPU_HOTPLUG infrastructure arm64: add PSCI CPU_OFF-based hotplug support HACK: arm64: dts: foundation: add PSCI data
arch/arm64/Kconfig | 2 +- arch/arm64/boot/dts/foundation-v8.dts | 19 +-- arch/arm64/include/asm/irq.h | 1 + arch/arm64/include/asm/smp.h | 46 +++++-- arch/arm64/kernel/cputable.c | 2 +- arch/arm64/kernel/head.S | 12 +- arch/arm64/kernel/irq.c | 61 +++++++++ arch/arm64/kernel/process.c | 7 ++ arch/arm64/kernel/smp.c | 222 ++++++++++++++++++--------------- arch/arm64/kernel/smp_psci.c | 54 ++++++-- arch/arm64/kernel/smp_spin_table.c | 85 ++++++++++++- arch/arm64/kernel/vmlinux.lds.S | 1 - drivers/acpi/Kconfig | 10 ++ drivers/acpi/Makefile | 1 + drivers/acpi/plat/arm/boot.c | 20 +-- drivers/acpi/sci_emu.c | 145 +++++++++++++++++++++ 16 files changed, 538 insertions(+), 150 deletions(-) create mode 100644 drivers/acpi/sci_emu.c
-- 1.7.9.5
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi