Merge branch 'depends/rmk/smp' into tmp

This commit is contained in:
Arnd Bergmann 2011-10-20 17:57:46 +02:00
commit fcd467137e
16 changed files with 298 additions and 13 deletions

View File

@ -1407,6 +1407,31 @@ config SMP_ON_UP
If you don't know what to do here, say Y. If you don't know what to do here, say Y.
config ARM_CPU_TOPOLOGY
bool "Support cpu topology definition"
depends on SMP && CPU_V7
default y
help
Support ARM cpu topology definition. The MPIDR register defines
affinity between processors which is then used to describe the cpu
topology of an ARM System.
config SCHED_MC
bool "Multi-core scheduler support"
depends on ARM_CPU_TOPOLOGY
help
Multi-core scheduler support improves the CPU scheduler's decision
making when dealing with multi-core CPU chips at a cost of slightly
increased overhead in some places. If unsure say N here.
config SCHED_SMT
bool "SMT scheduler support"
depends on ARM_CPU_TOPOLOGY
help
Improves the CPU scheduler's decision making when dealing with
MultiThreading at a cost of slightly increased overhead in some
places. If unsure say N here.
config HAVE_ARM_SCU config HAVE_ARM_SCU
bool bool
help help

View File

@ -180,7 +180,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
return -EINVAL; return -EINVAL;
mask = 0xff << shift; mask = 0xff << shift;
bit = 1 << (cpu + shift); bit = 1 << (cpu_logical_map(cpu) + shift);
spin_lock(&irq_controller_lock); spin_lock(&irq_controller_lock);
val = readl_relaxed(reg) & ~mask; val = readl_relaxed(reg) & ~mask;
@ -259,9 +259,15 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
unsigned int irq_start) unsigned int irq_start)
{ {
unsigned int gic_irqs, irq_limit, i; unsigned int gic_irqs, irq_limit, i;
u32 cpumask;
void __iomem *base = gic->dist_base; void __iomem *base = gic->dist_base;
u32 cpumask = 1 << smp_processor_id(); u32 cpu = 0;
#ifdef CONFIG_SMP
cpu = cpu_logical_map(smp_processor_id());
#endif
cpumask = 1 << cpu;
cpumask |= cpumask << 8; cpumask |= cpumask << 8;
cpumask |= cpumask << 16; cpumask |= cpumask << 16;
@ -382,7 +388,12 @@ void __cpuinit gic_enable_ppi(unsigned int irq)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{ {
unsigned long map = *cpus_addr(*mask); int cpu;
unsigned long map = 0;
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
map |= 1 << cpu_logical_map(cpu);
/* /*
* Ensure that stores to Normal memory are visible to the * Ensure that stores to Normal memory are visible to the

View File

@ -8,6 +8,7 @@
#define CPUID_CACHETYPE 1 #define CPUID_CACHETYPE 1
#define CPUID_TCM 2 #define CPUID_TCM 2
#define CPUID_TLBTYPE 3 #define CPUID_TLBTYPE 3
#define CPUID_MPIDR 5
#define CPUID_EXT_PFR0 "c1, 0" #define CPUID_EXT_PFR0 "c1, 0"
#define CPUID_EXT_PFR1 "c1, 1" #define CPUID_EXT_PFR1 "c1, 1"
@ -70,6 +71,11 @@ static inline unsigned int __attribute_const__ read_cpuid_tcmstatus(void)
return read_cpuid(CPUID_TCM); return read_cpuid(CPUID_TCM);
} }
static inline unsigned int __attribute_const__ read_cpuid_mpidr(void)
{
return read_cpuid(CPUID_MPIDR);
}
/* /*
* Intel's XScale3 core supports some v6 features (supersections, L2) * Intel's XScale3 core supports some v6 features (supersections, L2)
* but advertises itself as v5 as it does not support the v6 ISA. For * but advertises itself as v5 as it does not support the v6 ISA. For

View File

@ -0,0 +1,19 @@
/*
* Annotations for marking C functions as exception handlers.
*
* These should only be used for C functions that are called from the low
* level exception entry code and not any intervening C code.
*/
#ifndef __ASM_ARM_EXCEPTION_H
#define __ASM_ARM_EXCEPTION_H
#include <linux/ftrace.h>
#define __exception __attribute__((section(".exception.text")))
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#define __exception_irq_entry __irq_entry
#else
#define __exception_irq_entry __exception
#endif
#endif /* __ASM_ARM_EXCEPTION_H */

View File

@ -22,6 +22,10 @@ void percpu_timer_setup(void);
*/ */
asmlinkage void do_local_timer(struct pt_regs *); asmlinkage void do_local_timer(struct pt_regs *);
/*
* Called from C code
*/
void handle_local_timer(struct pt_regs *);
#ifdef CONFIG_LOCAL_TIMERS #ifdef CONFIG_LOCAL_TIMERS

View File

@ -32,6 +32,11 @@ extern void show_ipi_list(struct seq_file *, int);
*/ */
asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); asmlinkage void do_IPI(int ipinr, struct pt_regs *regs);
/*
* Called from C code, this handles an IPI.
*/
void handle_IPI(int ipinr, struct pt_regs *regs);
/* /*
* Setup the set of possible CPUs (via set_cpu_possible) * Setup the set of possible CPUs (via set_cpu_possible)
*/ */
@ -65,6 +70,12 @@ extern void platform_secondary_init(unsigned int cpu);
*/ */
extern void platform_smp_prepare_cpus(unsigned int); extern void platform_smp_prepare_cpus(unsigned int);
/*
* Logical CPU mapping.
*/
extern int __cpu_logical_map[NR_CPUS];
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
/* /*
* Initial data for bringing up a secondary CPU. * Initial data for bringing up a secondary CPU.
*/ */

View File

@ -62,13 +62,6 @@
#include <asm/outercache.h> #include <asm/outercache.h>
#define __exception __attribute__((section(".exception.text")))
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#define __exception_irq_entry __irq_entry
#else
#define __exception_irq_entry __exception
#endif
struct thread_info; struct thread_info;
struct task_struct; struct task_struct;

View File

@ -1,6 +1,39 @@
#ifndef _ASM_ARM_TOPOLOGY_H #ifndef _ASM_ARM_TOPOLOGY_H
#define _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> #include <asm-generic/topology.h>
#endif /* _ASM_ARM_TOPOLOGY_H */ #endif /* _ASM_ARM_TOPOLOGY_H */

View File

@ -66,6 +66,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
obj-$(CONFIG_CPU_HAS_PMU) += pmu.o obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
ifneq ($(CONFIG_ARCH_EBSA110),y) ifneq ($(CONFIG_ARCH_EBSA110),y)
obj-y += io.o obj-y += io.o

View File

@ -35,8 +35,8 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/ftrace.h>
#include <asm/exception.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>

View File

@ -16,7 +16,6 @@
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ftrace.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/cpu.h> #include <linux/cpu.h>
@ -31,6 +30,8 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/exception.h>
#include <asm/topology.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
@ -39,6 +40,7 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/localtimer.h> #include <asm/localtimer.h>
#include <asm/smp_plat.h>
/* /*
* as from 2.5, kernels no longer have an init_tasks structure * as from 2.5, kernels no longer have an init_tasks structure
@ -259,6 +261,20 @@ void __ref cpu_die(void)
} }
#endif /* CONFIG_HOTPLUG_CPU */ #endif /* CONFIG_HOTPLUG_CPU */
int __cpu_logical_map[NR_CPUS];
void __init smp_setup_processor_id(void)
{
int i;
u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
cpu_logical_map(0) = cpu;
for (i = 1; i < NR_CPUS; ++i)
cpu_logical_map(i) = i == cpu ? 0 : i;
printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
}
/* /*
* Called by both boot and secondaries to move global data into * Called by both boot and secondaries to move global data into
* per-processor storage. * per-processor storage.
@ -268,6 +284,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
cpu_info->loops_per_jiffy = loops_per_jiffy; cpu_info->loops_per_jiffy = loops_per_jiffy;
store_cpu_topology(cpuid);
} }
/* /*
@ -358,6 +376,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
{ {
unsigned int ncores = num_possible_cpus(); unsigned int ncores = num_possible_cpus();
init_cpu_topology();
smp_store_cpu_info(smp_processor_id()); smp_store_cpu_info(smp_processor_id());
/* /*
@ -459,6 +479,11 @@ static void ipi_timer(void)
#ifdef CONFIG_LOCAL_TIMERS #ifdef CONFIG_LOCAL_TIMERS
asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs) asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
{
handle_local_timer(regs);
}
void handle_local_timer(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs = set_irq_regs(regs);
int cpu = smp_processor_id(); int cpu = smp_processor_id();
@ -566,6 +591,11 @@ static void ipi_cpu_stop(unsigned int cpu)
* Main handler for inter-processor interrupts * Main handler for inter-processor interrupts
*/ */
asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
{
handle_IPI(ipinr, regs);
}
void handle_IPI(int ipinr, struct pt_regs *regs)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs = set_irq_regs(regs);

View File

@ -34,7 +34,7 @@ unsigned int __init scu_get_core_count(void __iomem *scu_base)
/* /*
* Enable the SCU * Enable the SCU
*/ */
void __init scu_enable(void __iomem *scu_base) void scu_enable(void __iomem *scu_base)
{ {
u32 scu_ctrl; u32 scu_ctrl;

148
arch/arm/kernel/topology.c Normal file
View File

@ -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();
}

View File

@ -27,6 +27,7 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/exception.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/traps.h> #include <asm/traps.h>

View File

@ -19,6 +19,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/exception.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/gpio.h> #include <mach/gpio.h>

View File

@ -20,6 +20,7 @@
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <asm/exception.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>