-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ARM: 7011/1: Add ARM cpu topology definition
The affinity between ARM processors is defined in the MPIDR register. We can identify which processors are in the same cluster, and which ones have performance interdependency. We can define the cpu topology of ARM platform, that is then used by sched_mc and sched_smt. The default state of sched_mc and sched_smt config is disable. When enabled, the behavior of the scheduler can be modified with sched_mc_power_savings and sched_smt_power_savings sysfs interfaces. Changes since v4 : * Remove unnecessary parentheses and blank lines Changes since v3 : * Update the format of printk message * Remove blank line Changes since v2 : * Update the commit message and some comments Changes since v1 : * Update the commit message * Add read_cpuid_mpidr in arch/arm/include/asm/cputype.h * Modify header of arch/arm/kernel/topology.c * Modify tests and manipulation of MPIDR's bitfields * Modify the place and dependancy of the config * Modify Noop functions Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org> Reviewed-by: Amit Kucheria <amit.kucheria@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
- Loading branch information
Vincent Guittot
authored and
Russell King
committed
Oct 17, 2011
1 parent
d0a7745
commit c9018aa
Showing
6 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,39 @@ | ||
#ifndef _ASM_ARM_TOPOLOGY_H | ||
#define _ASM_ARM_TOPOLOGY_H | ||
|
||
#ifdef CONFIG_ARM_CPU_TOPOLOGY | ||
|
||
#include <linux/cpumask.h> | ||
|
||
struct cputopo_arm { | ||
int thread_id; | ||
int core_id; | ||
int socket_id; | ||
cpumask_t thread_sibling; | ||
cpumask_t core_sibling; | ||
}; | ||
|
||
extern struct cputopo_arm cpu_topology[NR_CPUS]; | ||
|
||
#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) | ||
|
||
void init_cpu_topology(void); | ||
void store_cpu_topology(unsigned int cpuid); | ||
const struct cpumask *cpu_coregroup_mask(unsigned int cpu); | ||
|
||
#else | ||
|
||
static inline void init_cpu_topology(void) { } | ||
static inline void store_cpu_topology(unsigned int cpuid) { } | ||
|
||
#endif | ||
|
||
#include <asm-generic/topology.h> | ||
|
||
#endif /* _ASM_ARM_TOPOLOGY_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* | ||
* arch/arm/kernel/topology.c | ||
* | ||
* Copyright (C) 2011 Linaro Limited. | ||
* Written by: Vincent Guittot | ||
* | ||
* based on arch/sh/kernel/topology.c | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file "COPYING" in the main directory of this archive | ||
* for more details. | ||
*/ | ||
|
||
#include <linux/cpu.h> | ||
#include <linux/cpumask.h> | ||
#include <linux/init.h> | ||
#include <linux/percpu.h> | ||
#include <linux/node.h> | ||
#include <linux/nodemask.h> | ||
#include <linux/sched.h> | ||
|
||
#include <asm/cputype.h> | ||
#include <asm/topology.h> | ||
|
||
#define MPIDR_SMP_BITMASK (0x3 << 30) | ||
#define MPIDR_SMP_VALUE (0x2 << 30) | ||
|
||
#define MPIDR_MT_BITMASK (0x1 << 24) | ||
|
||
/* | ||
* These masks reflect the current use of the affinity levels. | ||
* The affinity level can be up to 16 bits according to ARM ARM | ||
*/ | ||
|
||
#define MPIDR_LEVEL0_MASK 0x3 | ||
#define MPIDR_LEVEL0_SHIFT 0 | ||
|
||
#define MPIDR_LEVEL1_MASK 0xF | ||
#define MPIDR_LEVEL1_SHIFT 8 | ||
|
||
#define MPIDR_LEVEL2_MASK 0xFF | ||
#define MPIDR_LEVEL2_SHIFT 16 | ||
|
||
struct cputopo_arm cpu_topology[NR_CPUS]; | ||
|
||
const struct cpumask *cpu_coregroup_mask(unsigned int cpu) | ||
{ | ||
return &cpu_topology[cpu].core_sibling; | ||
} | ||
|
||
/* | ||
* store_cpu_topology is called at boot when only one cpu is running | ||
* and with the mutex cpu_hotplug.lock locked, when several cpus have booted, | ||
* which prevents simultaneous write access to cpu_topology array | ||
*/ | ||
void store_cpu_topology(unsigned int cpuid) | ||
{ | ||
struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid]; | ||
unsigned int mpidr; | ||
unsigned int cpu; | ||
|
||
/* If the cpu topology has been already set, just return */ | ||
if (cpuid_topo->core_id != -1) | ||
return; | ||
|
||
mpidr = read_cpuid_mpidr(); | ||
|
||
/* create cpu topology mapping */ | ||
if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) { | ||
/* | ||
* This is a multiprocessor system | ||
* multiprocessor format & multiprocessor mode field are set | ||
*/ | ||
|
||
if (mpidr & MPIDR_MT_BITMASK) { | ||
/* core performance interdependency */ | ||
cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT) | ||
& MPIDR_LEVEL0_MASK; | ||
cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT) | ||
& MPIDR_LEVEL1_MASK; | ||
cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT) | ||
& MPIDR_LEVEL2_MASK; | ||
} else { | ||
/* largely independent cores */ | ||
cpuid_topo->thread_id = -1; | ||
cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT) | ||
& MPIDR_LEVEL0_MASK; | ||
cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT) | ||
& MPIDR_LEVEL1_MASK; | ||
} | ||
} else { | ||
/* | ||
* This is an uniprocessor system | ||
* we are in multiprocessor format but uniprocessor system | ||
* or in the old uniprocessor format | ||
*/ | ||
cpuid_topo->thread_id = -1; | ||
cpuid_topo->core_id = 0; | ||
cpuid_topo->socket_id = -1; | ||
} | ||
|
||
/* update core and thread sibling masks */ | ||
for_each_possible_cpu(cpu) { | ||
struct cputopo_arm *cpu_topo = &cpu_topology[cpu]; | ||
|
||
if (cpuid_topo->socket_id == cpu_topo->socket_id) { | ||
cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); | ||
if (cpu != cpuid) | ||
cpumask_set_cpu(cpu, | ||
&cpuid_topo->core_sibling); | ||
|
||
if (cpuid_topo->core_id == cpu_topo->core_id) { | ||
cpumask_set_cpu(cpuid, | ||
&cpu_topo->thread_sibling); | ||
if (cpu != cpuid) | ||
cpumask_set_cpu(cpu, | ||
&cpuid_topo->thread_sibling); | ||
} | ||
} | ||
} | ||
smp_wmb(); | ||
|
||
printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n", | ||
cpuid, cpu_topology[cpuid].thread_id, | ||
cpu_topology[cpuid].core_id, | ||
cpu_topology[cpuid].socket_id, mpidr); | ||
} | ||
|
||
/* | ||
* init_cpu_topology is called at boot when only one cpu is running | ||
* which prevent simultaneous write access to cpu_topology array | ||
*/ | ||
void init_cpu_topology(void) | ||
{ | ||
unsigned int cpu; | ||
|
||
/* init core mask */ | ||
for_each_possible_cpu(cpu) { | ||
struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]); | ||
|
||
cpu_topo->thread_id = -1; | ||
cpu_topo->core_id = -1; | ||
cpu_topo->socket_id = -1; | ||
cpumask_clear(&cpu_topo->core_sibling); | ||
cpumask_clear(&cpu_topo->thread_sibling); | ||
} | ||
smp_wmb(); | ||
} |