platsmp.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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 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 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 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 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. /*
  173. * enable SCU
  174. */
  175. scu_enable(scu_base);
  176. /*
  177. * Write the address of secondary startup into the
  178. * system-wide flags register. The boot monitor waits
  179. * until it receives a soft interrupt, and then the
  180. * secondary CPU branches to this address.
  181. */
  182. __raw_writel(virt_to_phys(cns3xxx_secondary_startup),
  183. (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0600));
  184. /*
  185. * Setup FIQ's for main cpu
  186. */
  187. cns3xxx_init_fiq();
  188. cns3xxx_set_fiq_regs(0);
  189. }
  190. extern void v6_dma_map_area(const void *, size_t, int);
  191. extern void v6_dma_unmap_area(const void *, size_t, int);
  192. extern void v6_dma_flush_range(const void *, const void *);
  193. extern void v6_flush_kern_dcache_area(void *, size_t);
  194. void fiq_dma_map_area(const void *addr, size_t size, int dir)
  195. {
  196. unsigned long flags;
  197. struct fiq_req *req;
  198. raw_local_irq_save(flags);
  199. /* currently, not possible to take cpu0 down, so only check cpu1 */
  200. if (!cpu_online(1)) {
  201. raw_local_irq_restore(flags);
  202. v6_dma_map_area(addr, size, dir);
  203. return;
  204. }
  205. req = this_cpu_ptr(&fiq_data);
  206. req->map.addr = addr;
  207. req->map.size = size;
  208. req->flags = dir | CNS3XXX_MAP_AREA;
  209. smp_mb();
  210. writel_relaxed(FIQ_GENERATE, req->reg);
  211. v6_dma_map_area(addr, size, dir);
  212. while (req->flags)
  213. barrier();
  214. raw_local_irq_restore(flags);
  215. }
  216. void fiq_dma_unmap_area(const void *addr, size_t size, int dir)
  217. {
  218. unsigned long flags;
  219. struct fiq_req *req;
  220. raw_local_irq_save(flags);
  221. /* currently, not possible to take cpu0 down, so only check cpu1 */
  222. if (!cpu_online(1)) {
  223. raw_local_irq_restore(flags);
  224. v6_dma_unmap_area(addr, size, dir);
  225. return;
  226. }
  227. req = this_cpu_ptr(&fiq_data);
  228. req->unmap.addr = addr;
  229. req->unmap.size = size;
  230. req->flags = dir | CNS3XXX_UNMAP_AREA;
  231. smp_mb();
  232. writel_relaxed(FIQ_GENERATE, req->reg);
  233. v6_dma_unmap_area(addr, size, dir);
  234. while (req->flags)
  235. barrier();
  236. raw_local_irq_restore(flags);
  237. }
  238. void fiq_dma_flush_range(const void *start, const void *end)
  239. {
  240. unsigned long flags;
  241. struct fiq_req *req;
  242. raw_local_irq_save(flags);
  243. /* currently, not possible to take cpu0 down, so only check cpu1 */
  244. if (!cpu_online(1)) {
  245. raw_local_irq_restore(flags);
  246. v6_dma_flush_range(start, end);
  247. return;
  248. }
  249. req = this_cpu_ptr(&fiq_data);
  250. req->flush.start = start;
  251. req->flush.end = end;
  252. req->flags = CNS3XXX_FLUSH_RANGE;
  253. smp_mb();
  254. writel_relaxed(FIQ_GENERATE, req->reg);
  255. v6_dma_flush_range(start, end);
  256. while (req->flags)
  257. barrier();
  258. raw_local_irq_restore(flags);
  259. }
  260. void fiq_flush_kern_dcache_area(void *addr, size_t size)
  261. {
  262. fiq_dma_flush_range(addr, addr + size);
  263. }
  264. struct smp_operations cns3xxx_smp_ops __initdata = {
  265. .smp_init_cpus = cns3xxx_smp_init_cpus,
  266. .smp_prepare_cpus = cns3xxx_smp_prepare_cpus,
  267. .smp_secondary_init = cns3xxx_secondary_init,
  268. .smp_boot_secondary = cns3xxx_boot_secondary,
  269. };