For kexec -p, the boot cpu can be not the cpu0, this causes the problem to alloc paca[]. In theory, there is no requirement to assign cpu's logical id as its present seq by device tree. But we have something like cpu_first_thread_sibling(), which makes assumption on the mapping inside a core. Hence partially changing the mapping, i.e. unbind the mapping of core while keep the mapping inside a core. After this patch, boot-cpu will always be mapped into the range [0,threads_per_core). Signed-off-by: Pingfan Liu <kernelfans@xxxxxxxxx> --- arch/powerpc/include/asm/smp.h | 1 + arch/powerpc/kernel/prom.c | 25 ++++++++++++++----------- arch/powerpc/kernel/setup-common.c | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index fac963e..1299100 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -30,6 +30,7 @@ #include <asm/percpu.h> extern int boot_cpuid; +extern int boot_cpuhwid; extern int spinning_secondaries; extern void cpu_die(void); diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index da67606..d0ebb25 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -315,8 +315,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, const __be32 *intserv; int i, nthreads; int len; - int found = -1; - int found_thread = 0; + bool found = false; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) @@ -341,8 +340,11 @@ static int __init early_init_dt_scan_cpus(unsigned long node, if (fdt_version(initial_boot_params) >= 2) { if (be32_to_cpu(intserv[i]) == fdt_boot_cpuid_phys(initial_boot_params)) { - found = boot_cpu_count; - found_thread = i; + /* always map the boot-cpu logical id into the + * the range of [0, thread_per_core) + */ + boot_cpuid = i; + found = true; } } else { /* @@ -351,8 +353,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node, * off secondary threads. */ if (of_get_flat_dt_prop(node, - "linux,boot-cpu", NULL) != NULL) - found = boot_cpu_count; + "linux,boot-cpu", NULL) != NULL) { + boot_cpuid = i; + found = true; + } } #ifdef CONFIG_SMP /* logical cpu id is always 0 on UP kernels */ @@ -361,13 +365,12 @@ static int __init early_init_dt_scan_cpus(unsigned long node, } /* Not the boot CPU */ - if (found < 0) + if (!found) return 0; - DBG("boot cpu: logical %d physical %d\n", found, - be32_to_cpu(intserv[found_thread])); - boot_cpuid = found; - set_hard_smp_processor_id(found, be32_to_cpu(intserv[found_thread])); + boot_cpuhwid = be32_to_cpu(intserv[boot_cpuid]); + DBG("boot cpu: logical %d physical %d\n", boot_cpuid, boot_cpuhwid); + set_hard_smp_processor_id(boot_cpuid, boot_cpuhwid); /* * PAPR defines "logical" PVR values for cpus that diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 66f7cc6..1a67344 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -86,6 +86,7 @@ struct machdep_calls *machine_id; EXPORT_SYMBOL(machine_id); int boot_cpuid = -1; +int boot_cpuhwid = -1; EXPORT_SYMBOL_GPL(boot_cpuid); /* @@ -459,11 +460,17 @@ static void __init cpu_init_thread_core_maps(int tpc) void __init smp_setup_cpu_maps(void) { struct device_node *dn; + struct device_node *boot_dn = NULL; + bool handling_bootdn = true; int cpu = 0; int nthreads = 1; DBG("smp_setup_cpu_maps()\n"); +again: + /* E.g. kexec will not boot from the 1st core. So firstly loop to find out + * the dn of boot-cpu, and map them onto [0, nthreads) + */ for_each_node_by_type(dn, "cpu") { const __be32 *intserv; __be32 cpu_be; @@ -488,6 +495,16 @@ void __init smp_setup_cpu_maps(void) nthreads = len / sizeof(int); + if (handling_bootdn) { + if (boot_cpuid < nthreads && + be32_to_cpu(intserv[boot_cpuid]) == boot_cpuhwid) { + boot_dn = dn; + } + if (boot_dn == NULL) + continue; + } else if (dn == boot_dn) + continue; + for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) { bool avail; @@ -509,6 +526,10 @@ void __init smp_setup_cpu_maps(void) of_node_put(dn); break; } + if (handling_bootdn) { + handling_bootdn = false; + goto again; + } } /* If no SMT supported, nthreads is forced to 1 */ -- 2.7.4 _______________________________________________ kexec mailing list kexec@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/kexec