2 * arch/arm/mach-ox820/platsmp.c
4 * Copyright (C) 2002 ARM Ltd.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #include <linux/init.h>
12 #include <linux/device.h>
13 #include <linux/jiffies.h>
14 #include <linux/smp.h>
16 #include <linux/dma-mapping.h>
17 #include <linux/cache.h>
18 #include <asm/cacheflush.h>
19 #include <asm/smp_scu.h>
20 #include <asm/tlbflush.h>
21 #include <asm/cputype.h>
22 #include <linux/delay.h>
25 #include <linux/irqchip/arm-gic.h>
26 #include <mach/iomap.h>
28 #include <mach/hardware.h>
29 #include <mach/irqs.h>
31 #ifdef CONFIG_DMA_CACHE_FIQ_BROADCAST
33 #define FIQ_GENERATE 0x00000002
34 #define OXNAS_MAP_AREA 0x01000000
35 #define OXNAS_UNMAP_AREA 0x02000000
36 #define OXNAS_FLUSH_RANGE 0x03000000
55 } ____cacheline_aligned
;
57 static struct fiq_handler fh
= {
61 DEFINE_PER_CPU(struct fiq_req
, fiq_data
);
63 static inline void __cpuinit
ox820_set_fiq_regs(unsigned int cpu
)
65 struct pt_regs FIQ_regs
;
66 struct fiq_req
*fiq_req
= &per_cpu(fiq_data
, !cpu
);
69 FIQ_regs
.ARM_ip
= (unsigned int)fiq_req
;
70 FIQ_regs
.ARM_sp
= (int)(cpu
? RPSC_IRQ_SOFT
: RPSA_IRQ_SOFT
);
71 fiq_req
->reg
= cpu
? RPSC_IRQ_SOFT
: RPSA_IRQ_SOFT
;
73 set_fiq_regs(&FIQ_regs
);
76 static void __init
ox820_init_fiq(void)
78 void *fiqhandler_start
;
79 unsigned int fiqhandler_length
;
82 fiqhandler_start
= &ox820_fiq_start
;
83 fiqhandler_length
= &ox820_fiq_end
- &ox820_fiq_start
;
90 set_fiq_handler(fiqhandler_start
, fiqhandler_length
);
92 writel(IRQ_SOFT
, RPSA_FIQ_IRQ_TO_FIQ
);
93 writel(1, RPSA_FIQ_ENABLE
);
94 writel(IRQ_SOFT
, RPSC_FIQ_IRQ_TO_FIQ
);
95 writel(1, RPSC_FIQ_ENABLE
);
98 void fiq_dma_map_area(const void *addr
, size_t size
, int dir
)
103 raw_local_irq_save(flags
);
104 /* currently, not possible to take cpu0 down, so only check cpu1 */
105 if (!cpu_online(1)) {
106 raw_local_irq_restore(flags
);
107 v6_dma_map_area(addr
, size
, dir
);
111 req
= this_cpu_ptr(&fiq_data
);
112 req
->map
.addr
= addr
;
113 req
->map
.size
= size
;
114 req
->flags
= dir
| OXNAS_MAP_AREA
;
117 writel_relaxed(FIQ_GENERATE
, req
->reg
);
119 v6_dma_map_area(addr
, size
, dir
);
123 raw_local_irq_restore(flags
);
126 void fiq_dma_unmap_area(const void *addr
, size_t size
, int dir
)
131 raw_local_irq_save(flags
);
132 /* currently, not possible to take cpu0 down, so only check cpu1 */
133 if (!cpu_online(1)) {
134 raw_local_irq_restore(flags
);
135 v6_dma_unmap_area(addr
, size
, dir
);
139 req
= this_cpu_ptr(&fiq_data
);
140 req
->unmap
.addr
= addr
;
141 req
->unmap
.size
= size
;
142 req
->flags
= dir
| OXNAS_UNMAP_AREA
;
145 writel_relaxed(FIQ_GENERATE
, req
->reg
);
147 v6_dma_unmap_area(addr
, size
, dir
);
151 raw_local_irq_restore(flags
);
154 void fiq_dma_flush_range(const void *start
, const void *end
)
159 raw_local_irq_save(flags
);
160 /* currently, not possible to take cpu0 down, so only check cpu1 */
161 if (!cpu_online(1)) {
162 raw_local_irq_restore(flags
);
163 v6_dma_flush_range(start
, end
);
167 req
= this_cpu_ptr(&fiq_data
);
169 req
->flush
.start
= start
;
170 req
->flush
.end
= end
;
171 req
->flags
= OXNAS_FLUSH_RANGE
;
174 writel_relaxed(FIQ_GENERATE
, req
->reg
);
176 v6_dma_flush_range(start
, end
);
181 raw_local_irq_restore(flags
);
184 void fiq_flush_kern_dcache_area(void *addr
, size_t size
)
186 fiq_dma_flush_range(addr
, addr
+ size
);
190 #define ox820_set_fiq_regs(cpu) do {} while (0) /* nothing */
191 #define ox820_init_fiq() do {} while (0) /* nothing */
193 #endif /* DMA_CACHE_FIQ_BROADCAST */
195 static DEFINE_SPINLOCK(boot_lock
);
197 void __cpuinit
ox820_secondary_init(unsigned int cpu
)
200 * Setup Secondary Core FIQ regs
202 ox820_set_fiq_regs(1);
205 * let the primary processor know we're out of the
206 * pen, then head off into the C entry point
208 write_pen_release(-1);
211 * Synchronise with the boot thread.
213 spin_lock(&boot_lock
);
214 spin_unlock(&boot_lock
);
217 int __cpuinit
ox820_boot_secondary(unsigned int cpu
, struct task_struct
*idle
)
219 unsigned long timeout
;
222 * Set synchronisation state between this boot processor
223 * and the secondary one
225 spin_lock(&boot_lock
);
228 * This is really belt and braces; we hold unintended secondary
229 * CPUs in the holding pen until we're ready for them. However,
230 * since we haven't sent them a soft interrupt, they shouldn't
233 write_pen_release(cpu
);
235 writel(1, IOMEM(OXNAS_GICN_BASE_VA(cpu
) + GIC_CPU_CTRL
));
238 * Send the secondary CPU a soft interrupt, thereby causing
239 * the boot monitor to read the system wide flags register,
240 * and branch to the address found there.
243 arch_send_wakeup_ipi_mask(cpumask_of(cpu
));
244 timeout
= jiffies
+ (1 * HZ
);
245 while (time_before(jiffies
, timeout
)) {
247 if (read_pen_release() == -1)
254 * now the secondary core is starting up let it run its
255 * calibrations, then wait for it to finish
257 spin_unlock(&boot_lock
);
259 return read_pen_release() != -1 ? -ENOSYS
: 0;
262 void *scu_base_addr(void)
264 return IOMEM(OXNAS_SCU_BASE_VA
);
268 * Initialise the CPU possible map early - this describes the CPUs
269 * which may be present or become present in the system.
271 static void __init
ox820_smp_init_cpus(void)
273 void __iomem
*scu_base
= scu_base_addr();
274 unsigned int i
, ncores
;
276 ncores
= scu_base
? scu_get_core_count(scu_base
) : 1;
279 if (ncores
> nr_cpu_ids
) {
280 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
285 for (i
= 0; i
< ncores
; i
++)
286 set_cpu_possible(i
, true);
289 static void __init
ox820_smp_prepare_cpus(unsigned int max_cpus
)
292 scu_enable(scu_base_addr());
295 * Write the address of secondary startup into the
296 * system-wide flags register. The BootMonitor waits
297 * until it receives a soft interrupt, and then the
298 * secondary CPU branches to this address.
300 writel(virt_to_phys(ox820_secondary_startup
),
301 HOLDINGPEN_LOCATION
);
304 ox820_set_fiq_regs(0);
307 struct smp_operations ox820_smp_ops __initdata
= {
308 .smp_init_cpus
= ox820_smp_init_cpus
,
309 .smp_prepare_cpus
= ox820_smp_prepare_cpus
,
310 .smp_secondary_init
= ox820_secondary_init
,
311 .smp_boot_secondary
= ox820_boot_secondary
,
312 #ifdef CONFIG_HOTPLUG_CPU
313 .cpu_die
= ox820_cpu_die
,