[RFC PATCH v2 0/2] ARM: MPIDR linearization

Lorenzo Pieralisi lorenzo.pieralisi at arm.com
Thu Jun 6 11:22:03 EDT 2013

This patchset is v2 of a previous posting:


v2 changes:

- rescheduled registers usage in compute_mpidr_hash macro

Cores in ARM SMP systems are identified through coprocessor registers,
so that every core, by executing a coprocessor read, can detect its own
identifier. The CPU identifier evolved from a simple CPU ID on ARM 11 MPcore
SMP, where the CPU ID was split in two subfields (CPU ID and CLUSTER ID)
to the v7 MPIDR, where the MPIDR[23:0] bits define three affinity levels
that can describe thread, core, cluster topology identifiers.
According to the ARM 11 MPcore TRM and for architecture versions later
than v7 (MPIDR), to the ARM ARM, the identifier registers format is as follows:

NR: non-relevant for identification

ARM11 MPCORE: CPU ID register

31                                    12 11          8 7       4 3        0
|                 NR                    |  CLUSTER ID |    NR   |  CPU ID |


31       24 23                 16 15                 8 7                  0
|   NR     |      AFFINITY 2     |     AFFINITY 1     |    AFFINITY 0     |

The split of CPU identifiers in multiple affinity levels implies that
the CPU ID, and later the MPIDR, cannot be used as simple indexes, since
the bit representation can contain holes:

eg 4 CPUs, in two separate clusters with two CPUs each:

CPU0: MPIDR = 0x0
CPU1: MPIDR = 0x1
CPU2: MPIDR = 0x100
CPU3: MPIDR = 0x101

In order to carry out operations that rely on the HW CPUID/MPIDR (CCI
disabling, context save/restore) the association of the CPU ID, or MPIDR
to an index is needed so that the CPU can be associated with a set of
resources. Resources look-up through the HW CPU ID is carried out in
code paths usually executed in power down procedures, that have to be
fast and look-up should be performed with few instructions that may be
executing in physical address space, with the MMU off.
In order to provide a fast conversion from [CPU ID, MPIDR] values to indexes
this set provides methods to build a simple collision-free hash function based
on shifting and OR'ing of CPU ID values, with shifts precomputed at boot by
scanning the cpu_logical_map entries (that contain the CPUID/MPIDR) of
possible CPUs.

By scanning the cpu_logical_map, the boot code detects how many bits are really
required to represent HW identifiers in the system and map them to a set of
buckets that actually represent the given index a HW id correspond to. The
hashing algorithm inherently takes advantage of a-priori knowledge of the
CPUIDs/MPIDRs allowed bits layout and it can be executed with few instructions
even in code paths where caching and the MMU are turned off (e.g resuming from
idle, S2R, hibernation).

One drawback of the current hashing algorithm is that it may result in a big
number of buckets if the recommendations on the CPUID/MPIDR layout are not
respected in the CPUID/MPIDR configuration; code warns on hash table
sizes bigger than 4 times the number of possible CPUs, which is a
symptom of a weird CPUID/MPIDR HW configuration and should be the exception
not the rule.

The first patch in the series provides a function that precomputes all
required hashing parameters by scanning the cpu_logical_map (that
contains HW identifiers), computes and stashes the hash parameters in a
structure exported to all kernel components for further usage.

The second patch fixes the current cpu_{suspend}/{resume} functionality,
so that all levels of CPUID/MPIDR are supported and cpu_{suspend}/{resume}
can be used on systems where affinity levels 1 and 2 are actually populated.
The fix carries out dynamic allocation of the array used to save the context
pointers, with size equal to the number of precomputed CPUID/MPIDR hash
buckets. To access the array, the CPUID/MPIDR values are hashed through the
algorithm built in patch 1 so that a hash value is retrieved and the array can
be indexed properly through it.

Context pointer array is allocated through kmalloc, so that it is made
up of a contiguous chunk of memory whose virtual address can be safely
converted to physical address (used in the MMU off path) through a
static mapping translation valid for all pages (if more than one) making
up the context pointer array. Context pointer array base address is
stashed in a structure easily retrieved in assembly through a pc relative
load that provides both virtual and physical address so that address
translation is not needed in the cpu_resume path, saving a few instructions.

Code will be improved later through dynamic patching so that the mask
and shifts in the hashing algorithm will be embedded in the assembly
instructions as immediates, removing the need for multiple loads to
memory to retrieve them at every given cpu_{suspend}/{resume} cycle.

Tested on TC2 (dual cluster 2x3 A15/A7 system) through CPU idle deep C-states
allowing A15 and A7 shutdown modes on both SMP and UP configurations.

Lorenzo Pieralisi (2):
  ARM: kernel: build MPIDR hash function data structure
  ARM: kernel: implement stack pointer save array through MPIDR hashing

 arch/arm/include/asm/smp_plat.h | 18 ++++++++
 arch/arm/include/asm/suspend.h  |  5 +++
 arch/arm/kernel/asm-offsets.c   |  6 +++
 arch/arm/kernel/setup.c         | 67 ++++++++++++++++++++++++++++
 arch/arm/kernel/sleep.S         | 97 +++++++++++++++++++++++++++++++++--------
 arch/arm/kernel/suspend.c       | 20 +++++++++
 6 files changed, 195 insertions(+), 18 deletions(-)


More information about the linux-arm-kernel mailing list