Merge branch 'ppi-irq-core-for-rmk' of git://github.com/mzyngier/arm-platforms into devel-stable
这个提交包含在:
@@ -73,6 +73,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
|
||||
obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
|
||||
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
|
||||
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
|
||||
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
|
||||
|
||||
ifneq ($(CONFIG_ARCH_EBSA110),y)
|
||||
obj-y += io.o
|
||||
|
@@ -35,8 +35,8 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/irq.h>
|
||||
@@ -58,9 +58,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
|
||||
#endif
|
||||
#ifdef CONFIG_SMP
|
||||
show_ipi_list(p, prec);
|
||||
#endif
|
||||
#ifdef CONFIG_LOCAL_TIMERS
|
||||
show_local_irqs(p, prec);
|
||||
#endif
|
||||
seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
|
||||
return 0;
|
||||
|
@@ -16,7 +16,6 @@
|
||||
#include <linux/cache.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/cpu.h>
|
||||
@@ -31,6 +30,8 @@
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/topology.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
@@ -39,6 +40,7 @@
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/localtimer.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
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
|
||||
* 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);
|
||||
|
||||
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();
|
||||
|
||||
init_cpu_topology();
|
||||
|
||||
smp_store_cpu_info(smp_processor_id());
|
||||
|
||||
/*
|
||||
@@ -437,10 +457,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
|
||||
for (i = 0; i < NR_IPI; i++)
|
||||
sum += __get_irq_stat(cpu, ipi_irqs[i]);
|
||||
|
||||
#ifdef CONFIG_LOCAL_TIMERS
|
||||
sum += __get_irq_stat(cpu, local_timer_irqs);
|
||||
#endif
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
@@ -457,33 +473,6 @@ static void ipi_timer(void)
|
||||
irq_exit();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LOCAL_TIMERS
|
||||
asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (local_timer_ack()) {
|
||||
__inc_irq_stat(cpu, local_timer_irqs);
|
||||
ipi_timer();
|
||||
}
|
||||
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
void show_local_irqs(struct seq_file *p, int prec)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
seq_printf(p, "%*s: ", prec, "LOC");
|
||||
|
||||
for_each_present_cpu(cpu)
|
||||
seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
|
||||
|
||||
seq_printf(p, " Local timer interrupts\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||
static void smp_timer_broadcast(const struct cpumask *mask)
|
||||
{
|
||||
@@ -534,7 +523,7 @@ static void percpu_timer_stop(void)
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
|
||||
|
||||
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
|
||||
local_timer_stop(evt);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -566,6 +555,11 @@ static void ipi_cpu_stop(unsigned int cpu)
|
||||
* Main handler for inter-processor interrupts
|
||||
*/
|
||||
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();
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
|
@@ -33,7 +33,7 @@ unsigned int __init scu_get_core_count(void __iomem *scu_base)
|
||||
/*
|
||||
* Enable the SCU
|
||||
*/
|
||||
void __init scu_enable(void __iomem *scu_base)
|
||||
void scu_enable(void __iomem *scu_base)
|
||||
{
|
||||
u32 scu_ctrl;
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/smp_twd.h>
|
||||
#include <asm/localtimer.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
|
||||
/* set up by the platform code */
|
||||
@@ -26,6 +27,8 @@ void __iomem *twd_base;
|
||||
|
||||
static unsigned long twd_timer_rate;
|
||||
|
||||
static struct clock_event_device __percpu **twd_evt;
|
||||
|
||||
static void twd_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *clk)
|
||||
{
|
||||
@@ -80,6 +83,12 @@ int twd_timer_ack(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void twd_timer_stop(struct clock_event_device *clk)
|
||||
{
|
||||
twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
|
||||
disable_percpu_irq(clk->irq);
|
||||
}
|
||||
|
||||
static void __cpuinit twd_calibrate_rate(void)
|
||||
{
|
||||
unsigned long count;
|
||||
@@ -119,11 +128,43 @@ static void __cpuinit twd_calibrate_rate(void)
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t twd_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
|
||||
|
||||
if (twd_timer_ack()) {
|
||||
evt->event_handler(evt);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the local clock events for a CPU.
|
||||
*/
|
||||
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
||||
{
|
||||
struct clock_event_device **this_cpu_clk;
|
||||
|
||||
if (!twd_evt) {
|
||||
int err;
|
||||
|
||||
twd_evt = alloc_percpu(struct clock_event_device *);
|
||||
if (!twd_evt) {
|
||||
pr_err("twd: can't allocate memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
err = request_percpu_irq(clk->irq, twd_handler,
|
||||
"twd", twd_evt);
|
||||
if (err) {
|
||||
pr_err("twd: can't register interrupt %d (%d)\n",
|
||||
clk->irq, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
twd_calibrate_rate();
|
||||
|
||||
clk->name = "local_timer";
|
||||
@@ -137,8 +178,10 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
|
||||
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
|
||||
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
|
||||
|
||||
this_cpu_clk = __this_cpu_ptr(twd_evt);
|
||||
*this_cpu_clk = clk;
|
||||
|
||||
clockevents_register_device(clk);
|
||||
|
||||
/* Make sure our local interrupt controller has this enabled */
|
||||
gic_enable_ppi(clk->irq);
|
||||
enable_percpu_irq(clk->irq, 0);
|
||||
}
|
||||
|
148
arch/arm/kernel/topology.c
普通文件
148
arch/arm/kernel/topology.c
普通文件
@@ -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();
|
||||
}
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/traps.h>
|
||||
|
在新工单中引用
屏蔽一个用户