platsmp.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * linux/arch/arm/mach-cns3xxx/platsmp.c
  3. *
  4. * Copyright (C) 2002 ARM Ltd.
  5. * Copyright 2012 Gateworks Corporation
  6. * Chris Lang <clang@gateworks.com>
  7. * Tim Harvey <tharvey@gateworks.com>
  8. *
  9. * All Rights Reserved
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. */
  15. #include <linux/init.h>
  16. #include <linux/errno.h>
  17. #include <linux/delay.h>
  18. #include <linux/device.h>
  19. #include <linux/jiffies.h>
  20. #include <linux/smp.h>
  21. #include <linux/io.h>
  22. #include <asm/cacheflush.h>
  23. #include <asm/smp_scu.h>
  24. #include <asm/unified.h>
  25. #include <asm/fiq.h>
  26. #include <mach/smp.h>
  27. #include "cns3xxx.h"
  28. static struct fiq_handler fh = {
  29. .name = "cns3xxx-fiq"
  30. };
  31. struct fiq_req {
  32. union {
  33. struct {
  34. const void *addr;
  35. size_t size;
  36. } map;
  37. struct {
  38. const void *addr;
  39. size_t size;
  40. } unmap;
  41. struct {
  42. const void *start;
  43. const void *end;
  44. } flush;
  45. };
  46. volatile uint flags;
  47. void __iomem *reg;
  48. } ____cacheline_aligned;
  49. extern unsigned int fiq_number[2];
  50. DEFINE_PER_CPU(struct fiq_req, fiq_data);
  51. #define FIQ_ENABLED 0x80000000
  52. #define FIQ_GENERATE 0x00010000
  53. #define CNS3XXX_MAP_AREA 0x01000000
  54. #define CNS3XXX_UNMAP_AREA 0x02000000
  55. #define CNS3XXX_FLUSH_RANGE 0x03000000
  56. extern void cns3xxx_secondary_startup(void);
  57. extern unsigned char cns3xxx_fiq_start, cns3xxx_fiq_end;
  58. #define SCU_CPU_STATUS 0x08
  59. static void __iomem *scu_base;
  60. static inline void __cpuinit cns3xxx_set_fiq_regs(unsigned int cpu)
  61. {
  62. struct pt_regs FIQ_regs;
  63. struct fiq_req *fiq_req = &per_cpu(fiq_data, !cpu);
  64. FIQ_regs.ARM_r8 = 0;
  65. FIQ_regs.ARM_ip = (unsigned int)fiq_req;
  66. FIQ_regs.ARM_sp = (int) MISC_FIQ_CPU(!cpu);
  67. fiq_req->reg = MISC_FIQ_CPU(!cpu);
  68. set_fiq_regs(&FIQ_regs);
  69. }
  70. static void __init cns3xxx_init_fiq(void)
  71. {
  72. void *fiqhandler_start;
  73. unsigned int fiqhandler_length;
  74. int ret;
  75. fiqhandler_start = &cns3xxx_fiq_start;
  76. fiqhandler_length = &cns3xxx_fiq_end - &cns3xxx_fiq_start;
  77. ret = claim_fiq(&fh);
  78. if (ret)
  79. return;
  80. set_fiq_handler(fiqhandler_start, fiqhandler_length);
  81. }
  82. /*
  83. * Write pen_release in a way that is guaranteed to be visible to all
  84. * observers, irrespective of whether they're taking part in coherency
  85. * or not. This is necessary for the hotplug code to work reliably.
  86. */
  87. static void __cpuinit write_pen_release(int val)
  88. {
  89. pen_release = val;
  90. smp_wmb();
  91. __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
  92. outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
  93. }
  94. static DEFINE_SPINLOCK(boot_lock);
  95. static void __cpuinit cns3xxx_secondary_init(unsigned int cpu)
  96. {
  97. /*
  98. * Setup Secondary Core FIQ regs
  99. */
  100. cns3xxx_set_fiq_regs(1);
  101. /*
  102. * let the primary processor know we're out of the
  103. * pen, then head off into the C entry point
  104. */
  105. write_pen_release(-1);
  106. /*
  107. * Synchronise with the boot thread.
  108. */
  109. spin_lock(&boot_lock);
  110. spin_unlock(&boot_lock);
  111. }
  112. static int __cpuinit cns3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
  113. {
  114. unsigned long timeout;
  115. /*
  116. * Set synchronisation state between this boot processor
  117. * and the secondary one
  118. */
  119. spin_lock(&boot_lock);
  120. /*
  121. * The secondary processor is waiting to be released from
  122. * the holding pen - release it, then wait for it to flag
  123. * that it has been released by resetting pen_release.
  124. *
  125. * Note that "pen_release" is the hardware CPU ID, whereas
  126. * "cpu" is Linux's internal ID.
  127. */
  128. write_pen_release(cpu);
  129. /*
  130. * Send the secondary CPU a soft interrupt, thereby causing
  131. * the boot monitor to read the system wide flags register,
  132. * and branch to the address found there.
  133. */
  134. arch_send_wakeup_ipi_mask(cpumask_of(cpu));;
  135. timeout = jiffies + (1 * HZ);
  136. while (time_before(jiffies, timeout)) {
  137. smp_rmb();
  138. if (pen_release == -1)
  139. break;
  140. udelay(10);
  141. }
  142. /*
  143. * now the secondary core is starting up let it run its
  144. * calibrations, then wait for it to finish
  145. */
  146. spin_unlock(&boot_lock);
  147. return pen_release != -1 ? -ENOSYS : 0;
  148. }
  149. /*
  150. * Initialise the CPU possible map early - this describes the CPUs
  151. * which may be present or become present in the system.
  152. */
  153. static void __init cns3xxx_smp_init_cpus(void)
  154. {
  155. unsigned int i, ncores;
  156. unsigned int status;
  157. scu_base = (void __iomem *) CNS3XXX_TC11MP_SCU_BASE_VIRT;
  158. /* for CNS3xxx SCU_CPU_STATUS must be examined instead of SCU_CONFIGURATION
  159. * used in scu_get_core_count
  160. */
  161. status = __raw_readl(scu_base + SCU_CPU_STATUS);
  162. for (i = 0; i < NR_CPUS+1; i++) {
  163. if (((status >> (i*2)) & 0x3) == 0)
  164. set_cpu_possible(i, true);
  165. else
  166. break;
  167. }
  168. ncores = i;
  169. }
  170. static void __init cns3xxx_smp_prepare_cpus(unsigned int max_cpus)
  171. {
  172. int i;
  173. /*
  174. * Initialise the present map, which describes the set of CPUs
  175. * actually populated at the present time.
  176. */
  177. for (i = 0; i < max_cpus; i++) {
  178. set_cpu_present(i, true);
  179. }
  180. /*
  181. * enable SCU
  182. */
  183. scu_enable(scu_base);
  184. /*
  185. * Write the address of secondary startup into the
  186. * system-wide flags register. The boot monitor waits
  187. * until it receives a soft interrupt, and then the
  188. * secondary CPU branches to this address.
  189. */
  190. __raw_writel(virt_to_phys(cns3xxx_secondary_startup),
  191. (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0600));
  192. /*
  193. * Setup FIQ's for main cpu
  194. */
  195. cns3xxx_init_fiq();
  196. cns3xxx_set_fiq_regs(0);
  197. }
  198. extern void v6_dma_map_area(const void *, size_t, int);
  199. extern void v6_dma_unmap_area(const void *, size_t, int);
  200. extern void v6_dma_flush_range(const void *, const void *);
  201. extern void v6_flush_kern_dcache_area(void *, size_t);
  202. void fiq_dma_map_area(const void *addr, size_t size, int dir)
  203. {
  204. unsigned long flags;
  205. struct fiq_req *req;
  206. raw_local_irq_save(flags);
  207. /* currently, not possible to take cpu0 down, so only check cpu1 */
  208. if (!cpu_online(1)) {
  209. raw_local_irq_restore(flags);
  210. v6_dma_map_area(addr, size, dir);
  211. return;
  212. }
  213. req = this_cpu_ptr(&fiq_data);
  214. req->map.addr = addr;
  215. req->map.size = size;
  216. req->flags = dir | CNS3XXX_MAP_AREA;
  217. smp_mb();
  218. writel_relaxed(FIQ_GENERATE, req->reg);
  219. v6_dma_map_area(addr, size, dir);
  220. while (req->flags)
  221. barrier();
  222. raw_local_irq_restore(flags);
  223. }
  224. void fiq_dma_unmap_area(const void *addr, size_t size, int dir)
  225. {
  226. unsigned long flags;
  227. struct fiq_req *req;
  228. raw_local_irq_save(flags);
  229. /* currently, not possible to take cpu0 down, so only check cpu1 */
  230. if (!cpu_online(1)) {
  231. raw_local_irq_restore(flags);
  232. v6_dma_unmap_area(addr, size, dir);
  233. return;
  234. }
  235. req = this_cpu_ptr(&fiq_data);
  236. req->unmap.addr = addr;
  237. req->unmap.size = size;
  238. req->flags = dir | CNS3XXX_UNMAP_AREA;
  239. smp_mb();
  240. writel_relaxed(FIQ_GENERATE, req->reg);
  241. v6_dma_unmap_area(addr, size, dir);
  242. while (req->flags)
  243. barrier();
  244. raw_local_irq_restore(flags);
  245. }
  246. void fiq_dma_flush_range(const void *start, const void *end)
  247. {
  248. unsigned long flags;
  249. struct fiq_req *req;
  250. raw_local_irq_save(flags);
  251. /* currently, not possible to take cpu0 down, so only check cpu1 */
  252. if (!cpu_online(1)) {
  253. raw_local_irq_restore(flags);
  254. v6_dma_flush_range(start, end);
  255. return;
  256. }
  257. req = this_cpu_ptr(&fiq_data);
  258. req->flush.start = start;
  259. req->flush.end = end;
  260. req->flags = CNS3XXX_FLUSH_RANGE;
  261. smp_mb();
  262. writel_relaxed(FIQ_GENERATE, req->reg);
  263. v6_dma_flush_range(start, end);
  264. while (req->flags)
  265. barrier();
  266. raw_local_irq_restore(flags);
  267. }
  268. void fiq_flush_kern_dcache_area(void *addr, size_t size)
  269. {
  270. fiq_dma_flush_range(addr, addr + size);
  271. }
  272. struct smp_operations cns3xxx_smp_ops __initdata = {
  273. .smp_init_cpus = cns3xxx_smp_init_cpus,
  274. .smp_prepare_cpus = cns3xxx_smp_prepare_cpus,
  275. .smp_secondary_init = cns3xxx_secondary_init,
  276. .smp_boot_secondary = cns3xxx_boot_secondary,
  277. };