diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-06 17:31:35 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-01-06 17:32:03 -0500 |
commit | 4ec3eb13634529c0bc7466658d84d0bbe3244aea (patch) | |
tree | b491daac2ccfc7b8ca88e171a43f66888463568a /arch/arm/mach-ux500 | |
parent | 24056f525051a9e186af28904b396320e18bf9a0 (diff) | |
parent | 15095bb0fe779c0403091bda7adce5fb3bb9ca35 (diff) |
Merge branch 'smp' into misc
Conflicts:
arch/arm/kernel/entry-armv.S
arch/arm/mm/ioremap.c
Diffstat (limited to 'arch/arm/mach-ux500')
-rw-r--r-- | arch/arm/mach-ux500/cpu.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-ux500/headsmp.S | 1 | ||||
-rw-r--r-- | arch/arm/mach-ux500/hotplug.c | 18 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/smp.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-ux500/platsmp.c | 73 |
5 files changed, 32 insertions, 71 deletions
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index 73fb1a551ec6..608a1372b172 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c | |||
@@ -75,14 +75,14 @@ void __init ux500_init_irq(void) | |||
75 | static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) | 75 | static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask) |
76 | { | 76 | { |
77 | /* wait for the operation to complete */ | 77 | /* wait for the operation to complete */ |
78 | while (readl(reg) & mask) | 78 | while (readl_relaxed(reg) & mask) |
79 | ; | 79 | ; |
80 | } | 80 | } |
81 | 81 | ||
82 | static inline void ux500_cache_sync(void) | 82 | static inline void ux500_cache_sync(void) |
83 | { | 83 | { |
84 | void __iomem *base = __io_address(UX500_L2CC_BASE); | 84 | void __iomem *base = __io_address(UX500_L2CC_BASE); |
85 | writel(0, base + L2X0_CACHE_SYNC); | 85 | writel_relaxed(0, base + L2X0_CACHE_SYNC); |
86 | ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); | 86 | ux500_cache_wait(base + L2X0_CACHE_SYNC, 1); |
87 | } | 87 | } |
88 | 88 | ||
@@ -107,7 +107,7 @@ static void ux500_l2x0_inv_all(void) | |||
107 | uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ | 107 | uint32_t l2x0_way_mask = (1<<16) - 1; /* Bitmask of active ways */ |
108 | 108 | ||
109 | /* invalidate all ways */ | 109 | /* invalidate all ways */ |
110 | writel(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); | 110 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); |
111 | ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); | 111 | ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); |
112 | ux500_cache_sync(); | 112 | ux500_cache_sync(); |
113 | } | 113 | } |
diff --git a/arch/arm/mach-ux500/headsmp.S b/arch/arm/mach-ux500/headsmp.S index a6be2cdf2b2f..64fa451edcfd 100644 --- a/arch/arm/mach-ux500/headsmp.S +++ b/arch/arm/mach-ux500/headsmp.S | |||
@@ -23,7 +23,6 @@ ENTRY(u8500_secondary_startup) | |||
23 | ldmia r4, {r5, r6} | 23 | ldmia r4, {r5, r6} |
24 | sub r4, r4, r5 | 24 | sub r4, r4, r5 |
25 | add r6, r6, r4 | 25 | add r6, r6, r4 |
26 | dsb | ||
27 | pen: ldr r7, [r6] | 26 | pen: ldr r7, [r6] |
28 | cmp r7, r0 | 27 | cmp r7, r0 |
29 | bne pen | 28 | bne pen |
diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c index b782a03024be..dd8037ebccf8 100644 --- a/arch/arm/mach-ux500/hotplug.c +++ b/arch/arm/mach-ux500/hotplug.c | |||
@@ -11,14 +11,11 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
14 | #include <linux/completion.h> | ||
15 | 14 | ||
16 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
17 | 16 | ||
18 | extern volatile int pen_release; | 17 | extern volatile int pen_release; |
19 | 18 | ||
20 | static DECLARE_COMPLETION(cpu_killed); | ||
21 | |||
22 | static inline void platform_do_lowpower(unsigned int cpu) | 19 | static inline void platform_do_lowpower(unsigned int cpu) |
23 | { | 20 | { |
24 | flush_cache_all(); | 21 | flush_cache_all(); |
@@ -38,7 +35,7 @@ static inline void platform_do_lowpower(unsigned int cpu) | |||
38 | 35 | ||
39 | int platform_cpu_kill(unsigned int cpu) | 36 | int platform_cpu_kill(unsigned int cpu) |
40 | { | 37 | { |
41 | return wait_for_completion_timeout(&cpu_killed, 5000); | 38 | return 1; |
42 | } | 39 | } |
43 | 40 | ||
44 | /* | 41 | /* |
@@ -48,19 +45,6 @@ int platform_cpu_kill(unsigned int cpu) | |||
48 | */ | 45 | */ |
49 | void platform_cpu_die(unsigned int cpu) | 46 | void platform_cpu_die(unsigned int cpu) |
50 | { | 47 | { |
51 | #ifdef DEBUG | ||
52 | unsigned int this_cpu = hard_smp_processor_id(); | ||
53 | |||
54 | if (cpu != this_cpu) { | ||
55 | printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", | ||
56 | this_cpu, cpu); | ||
57 | BUG(); | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); | ||
62 | complete(&cpu_killed); | ||
63 | |||
64 | /* directly enter low power state, skipping secure registers */ | 48 | /* directly enter low power state, skipping secure registers */ |
65 | platform_do_lowpower(cpu); | 49 | platform_do_lowpower(cpu); |
66 | } | 50 | } |
diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h index 197e8417375e..ca2b15b1b3b1 100644 --- a/arch/arm/mach-ux500/include/mach/smp.h +++ b/arch/arm/mach-ux500/include/mach/smp.h | |||
@@ -10,7 +10,6 @@ | |||
10 | #define ASMARM_ARCH_SMP_H | 10 | #define ASMARM_ARCH_SMP_H |
11 | 11 | ||
12 | #include <asm/hardware/gic.h> | 12 | #include <asm/hardware/gic.h> |
13 | #include <asm/smp_mpidr.h> | ||
14 | 13 | ||
15 | /* This is required to wakeup the secondary core */ | 14 | /* This is required to wakeup the secondary core */ |
16 | extern void u8500_secondary_startup(void); | 15 | extern void u8500_secondary_startup(void); |
@@ -18,8 +17,8 @@ extern void u8500_secondary_startup(void); | |||
18 | /* | 17 | /* |
19 | * We use IRQ1 as the IPI | 18 | * We use IRQ1 as the IPI |
20 | */ | 19 | */ |
21 | static inline void smp_cross_call(const struct cpumask *mask) | 20 | static inline void smp_cross_call(const struct cpumask *mask, int ipi) |
22 | { | 21 | { |
23 | gic_raise_softirq(mask, 1); | 22 | gic_raise_softirq(mask, ipi); |
24 | } | 23 | } |
25 | #endif | 24 | #endif |
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 9e4c678de785..f71175a766d7 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | 19 | ||
20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
21 | #include <asm/localtimer.h> | ||
22 | #include <asm/smp_scu.h> | 21 | #include <asm/smp_scu.h> |
23 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
24 | 23 | ||
@@ -28,17 +27,23 @@ | |||
28 | */ | 27 | */ |
29 | volatile int __cpuinitdata pen_release = -1; | 28 | volatile int __cpuinitdata pen_release = -1; |
30 | 29 | ||
31 | static unsigned int __init get_core_count(void) | 30 | /* |
31 | * Write pen_release in a way that is guaranteed to be visible to all | ||
32 | * observers, irrespective of whether they're taking part in coherency | ||
33 | * or not. This is necessary for the hotplug code to work reliably. | ||
34 | */ | ||
35 | static void write_pen_release(int val) | ||
32 | { | 36 | { |
33 | return scu_get_core_count(__io_address(UX500_SCU_BASE)); | 37 | pen_release = val; |
38 | smp_wmb(); | ||
39 | __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); | ||
40 | outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); | ||
34 | } | 41 | } |
35 | 42 | ||
36 | static DEFINE_SPINLOCK(boot_lock); | 43 | static DEFINE_SPINLOCK(boot_lock); |
37 | 44 | ||
38 | void __cpuinit platform_secondary_init(unsigned int cpu) | 45 | void __cpuinit platform_secondary_init(unsigned int cpu) |
39 | { | 46 | { |
40 | trace_hardirqs_off(); | ||
41 | |||
42 | /* | 47 | /* |
43 | * if any interrupts are already enabled for the primary | 48 | * if any interrupts are already enabled for the primary |
44 | * core (e.g. timer irq), then they will not have been enabled | 49 | * core (e.g. timer irq), then they will not have been enabled |
@@ -50,7 +55,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) | |||
50 | * let the primary processor know we're out of the | 55 | * let the primary processor know we're out of the |
51 | * pen, then head off into the C entry point | 56 | * pen, then head off into the C entry point |
52 | */ | 57 | */ |
53 | pen_release = -1; | 58 | write_pen_release(-1); |
54 | 59 | ||
55 | /* | 60 | /* |
56 | * Synchronise with the boot thread. | 61 | * Synchronise with the boot thread. |
@@ -74,11 +79,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
74 | * the holding pen - release it, then wait for it to flag | 79 | * the holding pen - release it, then wait for it to flag |
75 | * that it has been released by resetting pen_release. | 80 | * that it has been released by resetting pen_release. |
76 | */ | 81 | */ |
77 | pen_release = cpu; | 82 | write_pen_release(cpu); |
78 | __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); | ||
79 | outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1); | ||
80 | 83 | ||
81 | smp_cross_call(cpumask_of(cpu)); | 84 | smp_cross_call(cpumask_of(cpu), 1); |
82 | 85 | ||
83 | timeout = jiffies + (1 * HZ); | 86 | timeout = jiffies + (1 * HZ); |
84 | while (time_before(jiffies, timeout)) { | 87 | while (time_before(jiffies, timeout)) { |
@@ -97,9 +100,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
97 | 100 | ||
98 | static void __init wakeup_secondary(void) | 101 | static void __init wakeup_secondary(void) |
99 | { | 102 | { |
100 | /* nobody is to be released from the pen yet */ | ||
101 | pen_release = -1; | ||
102 | |||
103 | /* | 103 | /* |
104 | * write the address of secondary startup into the backup ram register | 104 | * write the address of secondary startup into the backup ram register |
105 | * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the | 105 | * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the |
@@ -126,40 +126,26 @@ static void __init wakeup_secondary(void) | |||
126 | */ | 126 | */ |
127 | void __init smp_init_cpus(void) | 127 | void __init smp_init_cpus(void) |
128 | { | 128 | { |
129 | unsigned int i, ncores = get_core_count(); | 129 | unsigned int i, ncores; |
130 | 130 | ||
131 | for (i = 0; i < ncores; i++) | 131 | ncores = scu_get_core_count(__io_address(UX500_SCU_BASE)); |
132 | set_cpu_possible(i, true); | ||
133 | } | ||
134 | |||
135 | void __init smp_prepare_cpus(unsigned int max_cpus) | ||
136 | { | ||
137 | unsigned int ncores = get_core_count(); | ||
138 | unsigned int cpu = smp_processor_id(); | ||
139 | int i; | ||
140 | 132 | ||
141 | /* sanity check */ | 133 | /* sanity check */ |
142 | if (ncores == 0) { | 134 | if (ncores > NR_CPUS) { |
143 | printk(KERN_ERR | ||
144 | "U8500: strange CM count of 0? Default to 1\n"); | ||
145 | ncores = 1; | ||
146 | } | ||
147 | |||
148 | if (ncores > num_possible_cpus()) { | ||
149 | printk(KERN_WARNING | 135 | printk(KERN_WARNING |
150 | "U8500: no. of cores (%d) greater than configured " | 136 | "U8500: no. of cores (%d) greater than configured " |
151 | "maximum of %d - clipping\n", | 137 | "maximum of %d - clipping\n", |
152 | ncores, num_possible_cpus()); | 138 | ncores, NR_CPUS); |
153 | ncores = num_possible_cpus(); | 139 | ncores = NR_CPUS; |
154 | } | 140 | } |
155 | 141 | ||
156 | smp_store_cpu_info(cpu); | 142 | for (i = 0; i < ncores; i++) |
143 | set_cpu_possible(i, true); | ||
144 | } | ||
157 | 145 | ||
158 | /* | 146 | void __init platform_smp_prepare_cpus(unsigned int max_cpus) |
159 | * are we trying to boot more cores than exist? | 147 | { |
160 | */ | 148 | int i; |
161 | if (max_cpus > ncores) | ||
162 | max_cpus = ncores; | ||
163 | 149 | ||
164 | /* | 150 | /* |
165 | * Initialise the present map, which describes the set of CPUs | 151 | * Initialise the present map, which describes the set of CPUs |
@@ -168,13 +154,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
168 | for (i = 0; i < max_cpus; i++) | 154 | for (i = 0; i < max_cpus; i++) |
169 | set_cpu_present(i, true); | 155 | set_cpu_present(i, true); |
170 | 156 | ||
171 | if (max_cpus > 1) { | 157 | scu_enable(__io_address(UX500_SCU_BASE)); |
172 | /* | 158 | wakeup_secondary(); |
173 | * Enable the local timer or broadcast device for the | ||
174 | * boot CPU, but only if we have more than one CPU. | ||
175 | */ | ||
176 | percpu_timer_setup(); | ||
177 | scu_enable(__io_address(UX500_SCU_BASE)); | ||
178 | wakeup_secondary(); | ||
179 | } | ||
180 | } | 159 | } |