diff mbox

[1/4] arm64: topology: Implement basic CPU topology support

Message ID 20140225165411.GA3883@red-moon
State New
Headers show

Commit Message

Lorenzo Pieralisi Feb. 25, 2014, 4:54 p.m. UTC
Hi Mark,

On Tue, Feb 25, 2014 at 04:25:42AM +0000, Mark Brown wrote:
> From: Mark Brown <broonie@linaro.org>
> 
> Add basic CPU topology support to arm64, based on the existing pre-v8
> code and some work done by Mark Hambleton.  This patch does not
> implement any topology discovery support since that should be based on
> information from firmware, it merely implements the scaffolding for
> integration of topology support in the architecture.
> 
> No locking of the topology data is done since it is only modified during
> CPU bringup with external serialisation from the SMP code.
> 
> The goal is to separate the architecture hookup for providing topology
> information from the DT parsing in order to ease review and avoid
> blocking the architecture code (which will be built on by other work)
> with the DT code review by providing something simple and basic.
> 
> A following patch will implement support for parsing the DT topology
> bindings for ARM, similar patches will be needed for ACPI.
> 
> Signed-off-by: Mark Brown <broonie@linaro.org>

I have been clobbering the code with some random dts configs, running on
top of the patch attached (to make code compliant with default if DT
info is missing for some CPUs). Can you give it a go please and run your
tests against it (I have just put it together) ? It should simplify things,
thoughts ?

AFAIK it should be correct, at least the info required by the scheduler
is reset to default (include/linux/topology.h) if DT nodes are
misconfigured. It applies on top of your series.

Thanks,
Lorenzo

-- >8 --
Subject: [PATCH] arm64: kernel: update topology discovery code

If the device tree does not contain topology information for a CPU,
kernel code should set-up topology information for the CPU according
to the default values defined in Documentation/cputopology.txt.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
 arch/arm64/kernel/topology.c |   34 +++++++++++++---------------------
 1 files changed, 13 insertions(+), 21 deletions(-)

Comments

Lorenzo Pieralisi Feb. 26, 2014, 12:32 p.m. UTC | #1
On Wed, Feb 26, 2014 at 12:50:52AM +0000, Mark Brown wrote:
> On Tue, Feb 25, 2014 at 04:54:11PM +0000, Lorenzo Pieralisi wrote:
> Can I suggest that given the sort of thing we're looking at here it
> might be easier to apply the code as-is and then do any further work
> incrementally?

I think we have enough information to make code complete now, at least
for the topology code, I prefer to merge what's considered to be final.

> > If the device tree does not contain topology information for a CPU,
> > kernel code should set-up topology information for the CPU according
> > to the default values defined in Documentation/cputopology.txt.
> 
> > +		pr_warn("CPU%u: No topology information configured\n", cpuid);
> > +		cpuid_topo->core_id = 0;
> 
> I know this is what the document says and the scheduler copes but it
> does make me a bit nervous if we end up with only some CPUs in this
> undefined state.  I can't point to any practical problems and it's
> going to be the scheduler's fault if it does but I wouldn't be surprised
> if there were issues in cases where there is partial topology
> information (as opposed to either full topology information or none).
> 
> Having said that like I keep saying it seems most sensible to fall back
> to MPIDR if we don't have any better idea; it's guaranteed to be
> available, may well be correct and helps systems that did a good job
> with their hardware.

You have a point. Unless someone feels strongly against this, I would
suggest falling back to MPIDR_EL1 if there is missing or wrong information in
DT.

To do that, you need to scrap the structures initialized from DT
altogether if there is missing or wrong DT information, it is either DT for
all CPUs or MPIDR_EL1 for all CPUs, we can't mix the approaches (and while
at it I'd rather parse the HW MPIDR_EL1 so that you get get the MT bit
from it, which is not present in cpu_logical_map).

Let's sum it up:

- if there is a cpu-map, it takes precedence. If there are missing bits
  of info in the cpu-map we WARN_ON (since this is a firmware bug,
  cpu-map overrides MPIDR_EL1 registers info, if the information in cpu-map
  is wrong or missing we should flag it up and that deserves a WARN_ON)
- if cpu-map is missing, we fall back to MPIDR_EL1 and print a message
  just describing that.

I noticed you will have to add some macros to read MPIDR_EL1 bits in the
process.

Thanks,
Lorenzo
Catalin Marinas Feb. 26, 2014, 3:48 p.m. UTC | #2
On Wed, Feb 26, 2014 at 02:46:10PM +0000, Mark Brown wrote:
> On Wed, Feb 26, 2014 at 12:32:08PM +0000, Lorenzo Pieralisi wrote:
> > On Wed, Feb 26, 2014 at 12:50:52AM +0000, Mark Brown wrote:
> > > Having said that like I keep saying it seems most sensible to fall back
> > > to MPIDR if we don't have any better idea; it's guaranteed to be
> > > available, may well be correct and helps systems that did a good job
> > > with their hardware.
> 
> > You have a point. Unless someone feels strongly against this, I would
> > suggest falling back to MPIDR_EL1 if there is missing or wrong information in
> > DT.
> 
> Catalin seemed very concerned about any use at all of MPIDR, that's why
> the code was removed originally.  Catalin?

My concern is that the MPIDR is just considered a unique ID. The ARMv8
relaxes the requirement so that it no longer needs to start at 0 and
increase monotonically. I checked with the architecture guys here and
they still expect the affinity hierarchy to be described by MPIDR but we
can have holes in the range for certain levels (i.e. an affinity level
may not start at 0 and may not even increase monotonically for
subsequent CPUs).

So we can either add a tolerant MPIDR parsing or we simply assume that
the topology is _flat_ when DT doesn't provide the information.
Lorenzo Pieralisi Feb. 26, 2014, 5:50 p.m. UTC | #3
On Wed, Feb 26, 2014 at 03:48:58PM +0000, Catalin Marinas wrote:
> On Wed, Feb 26, 2014 at 02:46:10PM +0000, Mark Brown wrote:
> > On Wed, Feb 26, 2014 at 12:32:08PM +0000, Lorenzo Pieralisi wrote:
> > > On Wed, Feb 26, 2014 at 12:50:52AM +0000, Mark Brown wrote:
> > > > Having said that like I keep saying it seems most sensible to fall back
> > > > to MPIDR if we don't have any better idea; it's guaranteed to be
> > > > available, may well be correct and helps systems that did a good job
> > > > with their hardware.
> > 
> > > You have a point. Unless someone feels strongly against this, I would
> > > suggest falling back to MPIDR_EL1 if there is missing or wrong information in
> > > DT.
> > 
> > Catalin seemed very concerned about any use at all of MPIDR, that's why
> > the code was removed originally.  Catalin?
> 
> My concern is that the MPIDR is just considered a unique ID. The ARMv8
> relaxes the requirement so that it no longer needs to start at 0 and
> increase monotonically. I checked with the architecture guys here and
> they still expect the affinity hierarchy to be described by MPIDR but we
> can have holes in the range for certain levels (i.e. an affinity level
> may not start at 0 and may not even increase monotonically for
> subsequent CPUs).
> 
> So we can either add a tolerant MPIDR parsing or we simply assume that
> the topology is _flat_ when DT doesn't provide the information.

I think that as far as the topology structures are concerned we can fall
back to MPIDR_EL1 in case cpu-map is missing or incomplete, since even
if the affinity levels contain holes or are not sequential that should
be fine (but see below). After all we have cpu-map to correct things for
this same reason and that will take precedence over the MPIDR_EL1 anyway.

Macros below are required for the scheduler to work. The ids are arch
dependent (so generic code cannot rely on them being sequential or
follow any rule) and if we fall back to MPIDR_EL1 they will get initialized.

#define topology_physical_package_id(cpu)	(cpu_topology[cpu].socket_id)
#define topology_core_id(cpu)		(cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu)	(&cpu_topology[cpu].core_sibling)
#define topology_thread_cpumask(cpu)	(&cpu_topology[cpu].thread_sibling)

#define mc_capable()	(cpu_topology[0].socket_id != -1)
#define smt_capable()	(cpu_topology[0].thread_id != -1)

What would be wrong, is leaving the core_sibling and thread_sibling
masks empty and this CAN happen even on current arm32 code if the
cluster id field (ie MPIDR[15:8] for the sake of this discussion) is
different for different CPUs, and that's a bug that fortunately was
never hit (it is a totally valid MPIDR layout, a bit weird though).

On an arm32 4 cpus system with MPIDR layout {0x100, 0x200, 0x300, 0x400}
(which is allowed) the kernel would panic (since the thread_sibling and
core_sibling masks would end up empty).

So I agree with Catalin, either we allow a fall-back to MPIDR_EL1, with relaxed
parsing rules (but let's not forget what I wrote above), or we keep the
current set but with following changes:

- if s topology node for a cpu (or some cpus) is missing or wrong, the whole
  topology structure should be reverted to default (as in
  include/linux/topology.h Documentation/cputopology.txt). This solves Mark's
  concern about having some cpus with missing topology information.
  NB: My patch does not do that, it resets topology only for the misconfigured
  cpu.

That's the best we can do. I think that an MPIDR_EL1 fall back mechanism
should be put in place, as a separate patch or squashed to patch 1.

I would prefer the latter, but if you want to get the infrastructure in
first I think that's acceptable.

Apologies for all requested changes.

Thanks,
Lorenzo
diff mbox

Patch

diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index e85560a..22ce390 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -317,6 +317,18 @@  static void update_siblings_masks(unsigned int cpuid)
 	struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
 	int cpu;
 
+	if (cpuid_topo->cluster_id == -1) {
+		/*
+		 * DT does not contain topology information for this cpu
+		 * reset it to default behaviour
+		 */
+		pr_warn("CPU%u: No topology information configured\n", cpuid);
+		cpuid_topo->core_id = 0;
+		cpumask_set_cpu(cpuid, &cpuid_topo->core_sibling);
+		cpumask_set_cpu(cpuid, &cpuid_topo->thread_sibling);
+		return;
+	}
+
 	/* update core and thread sibling masks */
 	for_each_possible_cpu(cpu) {
 		cpu_topo = &cpu_topology[cpu];
@@ -339,14 +351,7 @@  static void update_siblings_masks(unsigned int cpuid)
 
 void store_cpu_topology(unsigned int cpuid)
 {
-	struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
-
-	/* Something should have picked a topology by the time we get here */
-	if (cpuid_topo->core_id == -1)
-		pr_warn("CPU%u: No topology information configured\n", cpuid);
-	else
-		update_siblings_masks(cpuid);
-
+	update_siblings_masks(cpuid);
 	update_cpu_power(cpuid);
 }
 
@@ -372,17 +377,4 @@  void __init init_cpu_topology(void)
 	}
 
 	parse_dt_topology();
-
-	/*
-	 * Assign all remaining CPUs to a cluster so the scheduler
-	 * doesn't get confused.
-	 */
-	for_each_possible_cpu(cpu) {
-		struct cpu_topology *cpu_topo = &cpu_topology[cpu];
-
-		if (cpu_topo->cluster_id == -1) {
-			cpu_topo->cluster_id = INT_MAX;
-			cpu_topo->core_id = cpu;
-		}
-	}
 }