Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 133b9731 authored by Yadu MG's avatar Yadu MG Committed by Gerrit - the friendly Code Review server
Browse files

arm64: Allow boot on cpus other than logical cpu 0



Kernel assumes boot cpu to be always on logical cpu 0.
At times there are benefits to boot kernel on other cpus
as well. On a heterogeneous multiprocessor system, booting
on a high-performance core can improve the boot time.

This patch removes the assumption that boot-cpu is logical
cpu 0. Device tree is looked up very early in boot to
determine the boot-cpus logical id. It also fixes hard-coding
of logical cpu 0 done at various places.

Change-Id: I27f1b2762db23a0af84fa5289f4b68ed31d84560
Signed-off-by: default avatarYadu MG <ymg@codeaurora.org>
parent 8136c468
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <linux/init.h>
#include <linux/threads.h>
#include <linux/cpu.h>

/**
 * struct cpu_operations - Callback operations for hotplugging CPUs.
@@ -68,7 +69,7 @@ int __init cpu_read_ops(int cpu);

static inline void __init cpu_read_bootcpu_ops(void)
{
	cpu_read_ops(0);
	cpu_read_ops(logical_bootcpu_id);
}

#endif /* ifndef __ASM_CPU_OPS_H */
+1 −1
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ static const char *__init cpu_read_enable_method(int cpu)
			 * when spin-table is used for secondaries).
			 * Don't warn spuriously.
			 */
			if (cpu != 0)
			if (cpu != logical_bootcpu_id)
				pr_err("%pOF: missing enable-method property\n",
					dn);
		}
+1 −1
Original line number Diff line number Diff line
@@ -387,7 +387,7 @@ void cpuinfo_store_cpu(void)

void __init cpuinfo_store_boot_cpu(void)
{
	struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
	struct cpuinfo_arm64 *info = &per_cpu(cpu_data, logical_bootcpu_id);
	__cpuinfo_store_cpu(info);

	boot_cpu_data = *info;
+87 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <linux/psci.h>
#include <linux/sched/task.h>
#include <linux/mm.h>
#include <linux/libfdt.h>

#include <asm/acpi.h>
#include <asm/fixmap.h>
@@ -99,10 +100,93 @@ static struct resource mem_res[] = {
 */
u64 __cacheline_aligned boot_args[4];

unsigned int logical_bootcpu_id __read_mostly;
EXPORT_SYMBOL(logical_bootcpu_id);

extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size,
				       pgprot_t prot);
/*
 * Parse the device tree cpu nodes and enumerate logical cpu number for
 * the boot cpu based on the mpidr value and reg value from the cpu node.
 * If the parsing fails at any point, value 0 will be returned which make
 * sure, we fallback to the default kernel behavior.
 */
static unsigned int __init parse_logical_bootcpu(u64 dt_phys)
{
	void *fdt;
	int size, parent, node, len;
	unsigned int logical_cpu_id = 0;
	fdt64_t *prop;
	u64 mpidr, hwid;

	/*
	 * Try to map the FDT early. If this fails, we simply bail,
	 * and proceed with logical cpu as 0. We will make another
	 * attempt at mapping the FDT in setup_machine()
	 */
	early_fixmap_init();
	fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
	if (!fdt)
		return 0;

	mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;

	parent = fdt_path_offset(fdt, "/cpus");
	if (parent < 0)
		return 0;
	/*
	 * Like of_parse_and_init_cpus(), we assume that the device tree
	 * entries for the dt nodes are defined in ascending order for
	 * populating cpu logical map.
	 */
	fdt_for_each_subnode(node, fdt, parent) {
		prop = fdt_getprop_w(fdt, node, "reg", &len);
		if (!prop || len != sizeof(u64))
			return 0;

		hwid = fdt64_to_cpu(*prop);
		if (hwid & ~MPIDR_HWID_BITMASK)
			return 0;

		/*
		 * If the cpu node reg value matches the currently active
		 * processor(boot cpu), we bail out from the loop.
		 */
		if (hwid == mpidr)
			return logical_cpu_id;

		logical_cpu_id++;

		if (logical_cpu_id >= NR_CPUS)
			return 0;
	}

	return 0;
}

DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);

/*
 * smp_processor_id() returns the current processor number which
 * internally uses per-cpu variable cpu_number. At this stage,
 * since per-cpu area is still not initialized and the kernel
 * cannot assume current processor number to be 0. This function
 * temporarily assigns the current processor to be logical_bootcpu_id,
 * which is essentially enumerated from the device tree. In later stages
 * of boot the appropriate values for cpu_number will be assigned with
 * the call to smp_prepare_cpus().
 */
static inline void fix_smp_processor_id(void)
{
	per_cpu(cpu_number, 0) = logical_bootcpu_id;
}

void __init smp_setup_processor_id(void)
{
	u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
	cpu_logical_map(0) = mpidr;
	logical_bootcpu_id = parse_logical_bootcpu(__fdt_pointer);

	cpu_logical_map(logical_bootcpu_id) = mpidr;

	/*
	 * clear __my_cpu_offset on boot CPU to avoid hang caused by
@@ -111,6 +195,8 @@ void __init smp_setup_processor_id(void)
	 */
	set_my_cpu_offset(0);
	pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);

	fix_smp_processor_id();
}

bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+24 −19
Original line number Diff line number Diff line
@@ -461,9 +461,12 @@ static bool __init is_mpidr_duplicate(unsigned int cpu, u64 hwid)
{
	unsigned int i;

	for (i = 1; (i < cpu) && (i < NR_CPUS); i++)
	for (i = 0; (i <= cpu) && (i < NR_CPUS); i++) {
		if (i == logical_bootcpu_id)
			continue;
		if (cpu_logical_map(i) == hwid)
			return true;
	}
	return false;
}

@@ -485,7 +488,7 @@ static int __init smp_cpu_setup(int cpu)
}

static bool bootcpu_valid __initdata;
static unsigned int cpu_count = 1;
static unsigned int cpu_count;

#ifdef CONFIG_ACPI
static struct acpi_madt_generic_interrupt cpu_madt_gicc[NR_CPUS];
@@ -522,7 +525,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
	}

	/* Check if GICC structure of boot CPU is available in the MADT */
	if (cpu_logical_map(0) == hwid) {
	if (cpu_logical_map(logical_bootcpu_id) == hwid) {
		if (bootcpu_valid) {
			pr_err("duplicate boot CPU MPIDR: 0x%llx in MADT\n",
			       hwid);
@@ -530,7 +533,8 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
		}
		bootcpu_valid = true;
		cpu_madt_gicc[0] = *processor;
		early_map_cpu_to_node(0, acpi_numa_get_nid(0, hwid));
		early_map_cpu_to_node(logical_bootcpu_id,
					acpi_numa_get_nid(0, hwid));
		return;
	}

@@ -583,7 +587,8 @@ DEFINE_PER_CPU(bool, pending_ipi);
/*
 * Enumerate the possible CPU set from the device tree and build the
 * cpu logical map array containing MPIDR values related to logical
 * cpus. Assumes that cpu_logical_map(0) has already been initialized.
 * cpus. Assumes that cpu_logical_map(logical_bootcpu_id) has already
 * been initialized.
 */
static void __init of_parse_and_init_cpus(void)
{
@@ -601,13 +606,7 @@ static void __init of_parse_and_init_cpus(void)
			goto next;
		}

		/*
		 * The numbering scheme requires that the boot CPU
		 * must be assigned logical id 0. Record it so that
		 * the logical map built from DT is validated and can
		 * be used.
		 */
		if (hwid == cpu_logical_map(0)) {
		if (hwid == cpu_logical_map(logical_bootcpu_id)) {
			if (bootcpu_valid) {
				pr_err("%pOF: duplicate boot cpu reg property in DT\n",
					dn);
@@ -615,15 +614,17 @@ static void __init of_parse_and_init_cpus(void)
			}

			bootcpu_valid = true;
			early_map_cpu_to_node(0, of_node_to_nid(dn));
			early_map_cpu_to_node(logical_bootcpu_id,
						of_node_to_nid(dn));

			/*
			 * cpu_logical_map has already been
			 * initialized and the boot cpu doesn't need
			 * the enable-method so continue without
			 * incrementing cpu.
			 * boot cpu's cpu_logical_map is already
			 * initialized and the boot cpu doesn't need the
			 * enable-method like secondary cpu's. Now, as we
			 * can't assume logical boot cpu to be 0, we need
			 * to loop through entire logical cpu map.
			 */
			continue;
			goto next;
		}

		if (cpu_count >= NR_CPUS)
@@ -674,8 +675,12 @@ void __init smp_init_cpus(void)
	 * with entries in cpu_logical_map while initializing the cpus.
	 * If the cpu set-up fails, invalidate the cpu_logical_map entry.
	 */
	for (i = 1; i < nr_cpu_ids; i++) {
	for (i = 0; i < nr_cpu_ids; i++) {
		if (cpu_logical_map(i) != INVALID_HWID) {
			if (cpu_logical_map(i) ==
					cpu_logical_map(logical_bootcpu_id))
				continue;

			if (smp_cpu_setup(i))
				cpu_logical_map(i) = INVALID_HWID;
		}
Loading