aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-10-23 09:42:30 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-10-23 09:42:30 -0400
commit34471a9168c8bfd7f0d00989a7b0797ad27d585e (patch)
tree847af3ec746c6357902cf57c7e12ba55a35eed30 /arch/arm/kernel
parentcefd3e71efca6f4ef7f06f1fc507771d76072741 (diff)
parent28af690a284dfcb627bd69d0963db1c0f412cb8c (diff)
Merge branch 'ppi-irq-core-for-rmk' of git://github.com/mzyngier/arm-platforms into devel-stable
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/irq.c5
-rw-r--r--arch/arm/kernel/smp.c60
-rw-r--r--arch/arm/kernel/smp_scu.c2
-rw-r--r--arch/arm/kernel/smp_twd.c47
-rw-r--r--arch/arm/kernel/topology.c148
-rw-r--r--arch/arm/kernel/traps.c1
7 files changed, 224 insertions, 40 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 8fa83f54c967..7cac26c5f502 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
73obj-$(CONFIG_CPU_HAS_PMU) += pmu.o 73obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
74obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o 74obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
75AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt 75AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
76obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
76 77
77ifneq ($(CONFIG_ARCH_EBSA110),y) 78ifneq ($(CONFIG_ARCH_EBSA110),y)
78 obj-y += io.o 79 obj-y += io.o
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index de3dcab8610b..7cb29261249a 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -35,8 +35,8 @@
35#include <linux/list.h> 35#include <linux/list.h>
36#include <linux/kallsyms.h> 36#include <linux/kallsyms.h>
37#include <linux/proc_fs.h> 37#include <linux/proc_fs.h>
38#include <linux/ftrace.h>
39 38
39#include <asm/exception.h>
40#include <asm/system.h> 40#include <asm/system.h>
41#include <asm/mach/arch.h> 41#include <asm/mach/arch.h>
42#include <asm/mach/irq.h> 42#include <asm/mach/irq.h>
@@ -59,9 +59,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
59#ifdef CONFIG_SMP 59#ifdef CONFIG_SMP
60 show_ipi_list(p, prec); 60 show_ipi_list(p, prec);
61#endif 61#endif
62#ifdef CONFIG_LOCAL_TIMERS
63 show_local_irqs(p, prec);
64#endif
65 seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); 62 seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
66 return 0; 63 return 0;
67} 64}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index d88ff0230e82..a96c08cd6125 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -16,7 +16,6 @@
16#include <linux/cache.h> 16#include <linux/cache.h>
17#include <linux/profile.h> 17#include <linux/profile.h>
18#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/ftrace.h>
20#include <linux/mm.h> 19#include <linux/mm.h>
21#include <linux/err.h> 20#include <linux/err.h>
22#include <linux/cpu.h> 21#include <linux/cpu.h>
@@ -31,6 +30,8 @@
31#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
32#include <asm/cpu.h> 31#include <asm/cpu.h>
33#include <asm/cputype.h> 32#include <asm/cputype.h>
33#include <asm/exception.h>
34#include <asm/topology.h>
34#include <asm/mmu_context.h> 35#include <asm/mmu_context.h>
35#include <asm/pgtable.h> 36#include <asm/pgtable.h>
36#include <asm/pgalloc.h> 37#include <asm/pgalloc.h>
@@ -39,6 +40,7 @@
39#include <asm/tlbflush.h> 40#include <asm/tlbflush.h>
40#include <asm/ptrace.h> 41#include <asm/ptrace.h>
41#include <asm/localtimer.h> 42#include <asm/localtimer.h>
43#include <asm/smp_plat.h>
42 44
43/* 45/*
44 * as from 2.5, kernels no longer have an init_tasks structure 46 * as from 2.5, kernels no longer have an init_tasks structure
@@ -259,6 +261,20 @@ void __ref cpu_die(void)
259} 261}
260#endif /* CONFIG_HOTPLUG_CPU */ 262#endif /* CONFIG_HOTPLUG_CPU */
261 263
264int __cpu_logical_map[NR_CPUS];
265
266void __init smp_setup_processor_id(void)
267{
268 int i;
269 u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
270
271 cpu_logical_map(0) = cpu;
272 for (i = 1; i < NR_CPUS; ++i)
273 cpu_logical_map(i) = i == cpu ? 0 : i;
274
275 printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
276}
277
262/* 278/*
263 * Called by both boot and secondaries to move global data into 279 * Called by both boot and secondaries to move global data into
264 * per-processor storage. 280 * per-processor storage.
@@ -268,6 +284,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
268 struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); 284 struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
269 285
270 cpu_info->loops_per_jiffy = loops_per_jiffy; 286 cpu_info->loops_per_jiffy = loops_per_jiffy;
287
288 store_cpu_topology(cpuid);
271} 289}
272 290
273/* 291/*
@@ -358,6 +376,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
358{ 376{
359 unsigned int ncores = num_possible_cpus(); 377 unsigned int ncores = num_possible_cpus();
360 378
379 init_cpu_topology();
380
361 smp_store_cpu_info(smp_processor_id()); 381 smp_store_cpu_info(smp_processor_id());
362 382
363 /* 383 /*
@@ -437,10 +457,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
437 for (i = 0; i < NR_IPI; i++) 457 for (i = 0; i < NR_IPI; i++)
438 sum += __get_irq_stat(cpu, ipi_irqs[i]); 458 sum += __get_irq_stat(cpu, ipi_irqs[i]);
439 459
440#ifdef CONFIG_LOCAL_TIMERS
441 sum += __get_irq_stat(cpu, local_timer_irqs);
442#endif
443
444 return sum; 460 return sum;
445} 461}
446 462
@@ -457,33 +473,6 @@ static void ipi_timer(void)
457 irq_exit(); 473 irq_exit();
458} 474}
459 475
460#ifdef CONFIG_LOCAL_TIMERS
461asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
462{
463 struct pt_regs *old_regs = set_irq_regs(regs);
464 int cpu = smp_processor_id();
465
466 if (local_timer_ack()) {
467 __inc_irq_stat(cpu, local_timer_irqs);
468 ipi_timer();
469 }
470
471 set_irq_regs(old_regs);
472}
473
474void show_local_irqs(struct seq_file *p, int prec)
475{
476 unsigned int cpu;
477
478 seq_printf(p, "%*s: ", prec, "LOC");
479
480 for_each_present_cpu(cpu)
481 seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
482
483 seq_printf(p, " Local timer interrupts\n");
484}
485#endif
486
487#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST 476#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
488static void smp_timer_broadcast(const struct cpumask *mask) 477static void smp_timer_broadcast(const struct cpumask *mask)
489{ 478{
@@ -534,7 +523,7 @@ static void percpu_timer_stop(void)
534 unsigned int cpu = smp_processor_id(); 523 unsigned int cpu = smp_processor_id();
535 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); 524 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
536 525
537 evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); 526 local_timer_stop(evt);
538} 527}
539#endif 528#endif
540 529
@@ -567,6 +556,11 @@ static void ipi_cpu_stop(unsigned int cpu)
567 */ 556 */
568asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) 557asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
569{ 558{
559 handle_IPI(ipinr, regs);
560}
561
562void handle_IPI(int ipinr, struct pt_regs *regs)
563{
570 unsigned int cpu = smp_processor_id(); 564 unsigned int cpu = smp_processor_id();
571 struct pt_regs *old_regs = set_irq_regs(regs); 565 struct pt_regs *old_regs = set_irq_regs(regs);
572 566
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 79ed5e7f204a..5b6d536cbfe3 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -33,7 +33,7 @@ unsigned int __init scu_get_core_count(void __iomem *scu_base)
33/* 33/*
34 * Enable the SCU 34 * Enable the SCU
35 */ 35 */
36void __init scu_enable(void __iomem *scu_base) 36void scu_enable(void __iomem *scu_base)
37{ 37{
38 u32 scu_ctrl; 38 u32 scu_ctrl;
39 39
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 01c186222f3b..a8a6682d6b52 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -19,6 +19,7 @@
19#include <linux/io.h> 19#include <linux/io.h>
20 20
21#include <asm/smp_twd.h> 21#include <asm/smp_twd.h>
22#include <asm/localtimer.h>
22#include <asm/hardware/gic.h> 23#include <asm/hardware/gic.h>
23 24
24/* set up by the platform code */ 25/* set up by the platform code */
@@ -26,6 +27,8 @@ void __iomem *twd_base;
26 27
27static unsigned long twd_timer_rate; 28static unsigned long twd_timer_rate;
28 29
30static struct clock_event_device __percpu **twd_evt;
31
29static void twd_set_mode(enum clock_event_mode mode, 32static void twd_set_mode(enum clock_event_mode mode,
30 struct clock_event_device *clk) 33 struct clock_event_device *clk)
31{ 34{
@@ -80,6 +83,12 @@ int twd_timer_ack(void)
80 return 0; 83 return 0;
81} 84}
82 85
86void twd_timer_stop(struct clock_event_device *clk)
87{
88 twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
89 disable_percpu_irq(clk->irq);
90}
91
83static void __cpuinit twd_calibrate_rate(void) 92static void __cpuinit twd_calibrate_rate(void)
84{ 93{
85 unsigned long count; 94 unsigned long count;
@@ -119,11 +128,43 @@ static void __cpuinit twd_calibrate_rate(void)
119 } 128 }
120} 129}
121 130
131static irqreturn_t twd_handler(int irq, void *dev_id)
132{
133 struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
134
135 if (twd_timer_ack()) {
136 evt->event_handler(evt);
137 return IRQ_HANDLED;
138 }
139
140 return IRQ_NONE;
141}
142
122/* 143/*
123 * Setup the local clock events for a CPU. 144 * Setup the local clock events for a CPU.
124 */ 145 */
125void __cpuinit twd_timer_setup(struct clock_event_device *clk) 146void __cpuinit twd_timer_setup(struct clock_event_device *clk)
126{ 147{
148 struct clock_event_device **this_cpu_clk;
149
150 if (!twd_evt) {
151 int err;
152
153 twd_evt = alloc_percpu(struct clock_event_device *);
154 if (!twd_evt) {
155 pr_err("twd: can't allocate memory\n");
156 return;
157 }
158
159 err = request_percpu_irq(clk->irq, twd_handler,
160 "twd", twd_evt);
161 if (err) {
162 pr_err("twd: can't register interrupt %d (%d)\n",
163 clk->irq, err);
164 return;
165 }
166 }
167
127 twd_calibrate_rate(); 168 twd_calibrate_rate();
128 169
129 clk->name = "local_timer"; 170 clk->name = "local_timer";
@@ -137,8 +178,10 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
137 clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); 178 clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
138 clk->min_delta_ns = clockevent_delta2ns(0xf, clk); 179 clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
139 180
181 this_cpu_clk = __this_cpu_ptr(twd_evt);
182 *this_cpu_clk = clk;
183
140 clockevents_register_device(clk); 184 clockevents_register_device(clk);
141 185
142 /* Make sure our local interrupt controller has this enabled */ 186 enable_percpu_irq(clk->irq, 0);
143 gic_enable_ppi(clk->irq);
144} 187}
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
new file mode 100644
index 000000000000..1040c00405d0
--- /dev/null
+++ b/arch/arm/kernel/topology.c
@@ -0,0 +1,148 @@
1/*
2 * arch/arm/kernel/topology.c
3 *
4 * Copyright (C) 2011 Linaro Limited.
5 * Written by: Vincent Guittot
6 *
7 * based on arch/sh/kernel/topology.c
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 */
13
14#include <linux/cpu.h>
15#include <linux/cpumask.h>
16#include <linux/init.h>
17#include <linux/percpu.h>
18#include <linux/node.h>
19#include <linux/nodemask.h>
20#include <linux/sched.h>
21
22#include <asm/cputype.h>
23#include <asm/topology.h>
24
25#define MPIDR_SMP_BITMASK (0x3 << 30)
26#define MPIDR_SMP_VALUE (0x2 << 30)
27
28#define MPIDR_MT_BITMASK (0x1 << 24)
29
30/*
31 * These masks reflect the current use of the affinity levels.
32 * The affinity level can be up to 16 bits according to ARM ARM
33 */
34
35#define MPIDR_LEVEL0_MASK 0x3
36#define MPIDR_LEVEL0_SHIFT 0
37
38#define MPIDR_LEVEL1_MASK 0xF
39#define MPIDR_LEVEL1_SHIFT 8
40
41#define MPIDR_LEVEL2_MASK 0xFF
42#define MPIDR_LEVEL2_SHIFT 16
43
44struct cputopo_arm cpu_topology[NR_CPUS];
45
46const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
47{
48 return &cpu_topology[cpu].core_sibling;
49}
50
51/*
52 * store_cpu_topology is called at boot when only one cpu is running
53 * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
54 * which prevents simultaneous write access to cpu_topology array
55 */
56void store_cpu_topology(unsigned int cpuid)
57{
58 struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
59 unsigned int mpidr;
60 unsigned int cpu;
61
62 /* If the cpu topology has been already set, just return */
63 if (cpuid_topo->core_id != -1)
64 return;
65
66 mpidr = read_cpuid_mpidr();
67
68 /* create cpu topology mapping */
69 if ((mpidr & MPIDR_SMP_BITMASK) == MPIDR_SMP_VALUE) {
70 /*
71 * This is a multiprocessor system
72 * multiprocessor format & multiprocessor mode field are set
73 */
74
75 if (mpidr & MPIDR_MT_BITMASK) {
76 /* core performance interdependency */
77 cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
78 & MPIDR_LEVEL0_MASK;
79 cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
80 & MPIDR_LEVEL1_MASK;
81 cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT)
82 & MPIDR_LEVEL2_MASK;
83 } else {
84 /* largely independent cores */
85 cpuid_topo->thread_id = -1;
86 cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
87 & MPIDR_LEVEL0_MASK;
88 cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
89 & MPIDR_LEVEL1_MASK;
90 }
91 } else {
92 /*
93 * This is an uniprocessor system
94 * we are in multiprocessor format but uniprocessor system
95 * or in the old uniprocessor format
96 */
97 cpuid_topo->thread_id = -1;
98 cpuid_topo->core_id = 0;
99 cpuid_topo->socket_id = -1;
100 }
101
102 /* update core and thread sibling masks */
103 for_each_possible_cpu(cpu) {
104 struct cputopo_arm *cpu_topo = &cpu_topology[cpu];
105
106 if (cpuid_topo->socket_id == cpu_topo->socket_id) {
107 cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
108 if (cpu != cpuid)
109 cpumask_set_cpu(cpu,
110 &cpuid_topo->core_sibling);
111
112 if (cpuid_topo->core_id == cpu_topo->core_id) {
113 cpumask_set_cpu(cpuid,
114 &cpu_topo->thread_sibling);
115 if (cpu != cpuid)
116 cpumask_set_cpu(cpu,
117 &cpuid_topo->thread_sibling);
118 }
119 }
120 }
121 smp_wmb();
122
123 printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
124 cpuid, cpu_topology[cpuid].thread_id,
125 cpu_topology[cpuid].core_id,
126 cpu_topology[cpuid].socket_id, mpidr);
127}
128
129/*
130 * init_cpu_topology is called at boot when only one cpu is running
131 * which prevent simultaneous write access to cpu_topology array
132 */
133void init_cpu_topology(void)
134{
135 unsigned int cpu;
136
137 /* init core mask */
138 for_each_possible_cpu(cpu) {
139 struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
140
141 cpu_topo->thread_id = -1;
142 cpu_topo->core_id = -1;
143 cpu_topo->socket_id = -1;
144 cpumask_clear(&cpu_topo->core_sibling);
145 cpumask_clear(&cpu_topo->thread_sibling);
146 }
147 smp_wmb();
148}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bc9f9da782cb..210382555af1 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -27,6 +27,7 @@
27 27
28#include <linux/atomic.h> 28#include <linux/atomic.h>
29#include <asm/cacheflush.h> 29#include <asm/cacheflush.h>
30#include <asm/exception.h>
30#include <asm/system.h> 31#include <asm/system.h>
31#include <asm/unistd.h> 32#include <asm/unistd.h>
32#include <asm/traps.h> 33#include <asm/traps.h>