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

Commit 05ee953c authored by Zi Shen Lim's avatar Zi Shen Lim Committed by Rohit Vaswani
Browse files

arm64: topology: add MPIDR-based detection

Create cpu topology based on MPIDR. When hardware sets MPIDR to sane
values, this method will always work. Therefore it should also work well
as the fallback method. [1]

When we have multiple processing elements in the system, we create
the cpu topology by mapping each affinity level (from lowest to highest)
to threads (if they exist), cores, and clusters.

We combine data from all higher affinity levels into cluster_id
so we don't lose any information from MPIDR. [2]

[1] http://www.spinics.net/lists/arm-kernel/msg317445.html
[2] https://lkml.org/lkml/2014/4/23/703



[Raise the priority of the error message if we don't discover topology
now that we can read it from MPIDIR -- broonie]

Change-Id: I1e9dfd752f4ca0cb2309073439748dcbd0efa3be
Signed-off-by: default avatarZi Shen Lim <zlim@broadcom.com>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
Patch-mainline: linux-arm-kernel 5/2/2014, 20:38
Signed-off-by: default avatarRohit Vaswani <rvaswani@codeaurora.org>
parent c5746462
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#define INVALID_HWID		ULONG_MAX

#define MPIDR_UP_BITMASK	(0x1 << 30)
#define MPIDR_MT_BITMASK	(0x1 << 24)
#define MPIDR_HWID_BITMASK	0xff00ffffff

#define MPIDR_LEVEL_BITS_SHIFT	3
@@ -30,6 +32,9 @@
#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)

#define MPIDR_AFF_MASK(level) \
	((u64)MPIDR_LEVEL_MASK << MPIDR_LEVEL_SHIFT(level))

#define read_cpuid(reg) ({						\
	u64 __val;							\
	asm("mrs	%0, " #reg : "=r" (__val));			\
+42 −4
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <linux/of.h>
#include <linux/sched.h>

#include <asm/cputype.h>
#include <asm/smp_plat.h>
#include <asm/topology.h>

static int __init get_cpu_for_node(struct device_node *node)
@@ -220,10 +222,8 @@ static void update_siblings_masks(unsigned int cpuid)
	int cpu;

	if (cpuid_topo->cluster_id == -1) {
		/*
		 * DT does not contain topology information for this cpu.
		 */
		pr_debug("CPU%u: No topology information configured\n", cpuid);
		/* No topology information for this cpu ?! */
		pr_err("CPU%u: No topology information configured\n", cpuid);
		return;
	}

@@ -249,6 +249,44 @@ static void update_siblings_masks(unsigned int cpuid)

void store_cpu_topology(unsigned int cpuid)
{
	struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
	u64 mpidr;

	if (cpuid_topo->cluster_id != -1)
		goto topology_populated;

	mpidr = read_cpuid_mpidr();

	/* Create cpu topology mapping based on MPIDR. */
	if (mpidr & MPIDR_UP_BITMASK) {
		/* Uniprocessor system */
		cpuid_topo->thread_id  = -1;
		cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 0);
		cpuid_topo->cluster_id = 0;
	} else if (mpidr & MPIDR_MT_BITMASK) {
		/* Multiprocessor system : Multi-threads per core */
		cpuid_topo->thread_id  = MPIDR_AFFINITY_LEVEL(mpidr, 0);
		cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 1);
		cpuid_topo->cluster_id =
			((mpidr & MPIDR_AFF_MASK(2)) >> mpidr_hash.shift_aff[2] |
			 (mpidr & MPIDR_AFF_MASK(3)) >> mpidr_hash.shift_aff[3])
			>> mpidr_hash.shift_aff[1] >> mpidr_hash.shift_aff[0];
	} else {
		/* Multiprocessor system : Single-thread per core */
		cpuid_topo->thread_id  = -1;
		cpuid_topo->core_id    = MPIDR_AFFINITY_LEVEL(mpidr, 0);
		cpuid_topo->cluster_id =
			((mpidr & MPIDR_AFF_MASK(1)) >> mpidr_hash.shift_aff[1] |
			 (mpidr & MPIDR_AFF_MASK(2)) >> mpidr_hash.shift_aff[2] |
			 (mpidr & MPIDR_AFF_MASK(3)) >> mpidr_hash.shift_aff[3])
			>> mpidr_hash.shift_aff[0];
	}

	pr_debug("CPU%u: cluster %d core %d thread %d mpidr %llx\n",
		 cpuid, cpuid_topo->cluster_id, cpuid_topo->core_id,
		 cpuid_topo->thread_id, mpidr);

topology_populated:
	update_siblings_masks(cpuid);
}