smp-cmp.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * This program is free software; you can distribute it and/or modify it
  3. * under the terms of the GNU General Public License (Version 2) as
  4. * published by the Free Software Foundation.
  5. *
  6. * This program is distributed in the hope it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  9. * for more details.
  10. *
  11. * You should have received a copy of the GNU General Public License along
  12. * with this program; if not, write to the Free Software Foundation, Inc.,
  13. * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  14. *
  15. * Copyright (C) 2007 MIPS Technologies, Inc.
  16. * Chris Dearman (chris@mips.com)
  17. */
  18. #undef DEBUG
  19. #include <linux/kernel.h>
  20. #include <linux/sched.h>
  21. #include <linux/smp.h>
  22. #include <linux/cpumask.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/compiler.h>
  25. #include <asm/atomic.h>
  26. #include <asm/cacheflush.h>
  27. #include <asm/cpu.h>
  28. #include <asm/processor.h>
  29. #include <asm/system.h>
  30. #include <asm/hardirq.h>
  31. #include <asm/mmu_context.h>
  32. #include <asm/smp.h>
  33. #include <asm/time.h>
  34. #include <asm/mipsregs.h>
  35. #include <asm/mipsmtregs.h>
  36. #include <asm/mips_mt.h>
  37. /*
  38. * Crude manipulation of the CPU masks to control which
  39. * which CPU's are brought online during initialisation
  40. *
  41. * Beware... this needs to be called after CPU discovery
  42. * but before CPU bringup
  43. */
  44. static int __init allowcpus(char *str)
  45. {
  46. cpumask_t cpu_allow_map;
  47. char buf[256];
  48. int len;
  49. cpus_clear(cpu_allow_map);
  50. if (cpulist_parse(str, &cpu_allow_map) == 0) {
  51. cpu_set(0, cpu_allow_map);
  52. cpus_and(cpu_possible_map, cpu_possible_map, cpu_allow_map);
  53. len = cpulist_scnprintf(buf, sizeof(buf)-1, &cpu_possible_map);
  54. buf[len] = '\0';
  55. pr_debug("Allowable CPUs: %s\n", buf);
  56. return 1;
  57. } else
  58. return 0;
  59. }
  60. __setup("allowcpus=", allowcpus);
  61. static void ipi_call_function(unsigned int cpu)
  62. {
  63. unsigned int action = 0;
  64. pr_debug("CPU%d: %s cpu %d status %08x\n",
  65. smp_processor_id(), __func__, cpu, read_c0_status());
  66. switch (cpu) {
  67. case 0:
  68. action = GIC_IPI_EXT_INTR_CALLFNC_VPE0;
  69. break;
  70. case 1:
  71. action = GIC_IPI_EXT_INTR_CALLFNC_VPE1;
  72. break;
  73. case 2:
  74. action = GIC_IPI_EXT_INTR_CALLFNC_VPE2;
  75. break;
  76. case 3:
  77. action = GIC_IPI_EXT_INTR_CALLFNC_VPE3;
  78. break;
  79. }
  80. gic_send_ipi(action);
  81. }
  82. static void ipi_resched(unsigned int cpu)
  83. {
  84. unsigned int action = 0;
  85. pr_debug("CPU%d: %s cpu %d status %08x\n",
  86. smp_processor_id(), __func__, cpu, read_c0_status());
  87. switch (cpu) {
  88. case 0:
  89. action = GIC_IPI_EXT_INTR_RESCHED_VPE0;
  90. break;
  91. case 1:
  92. action = GIC_IPI_EXT_INTR_RESCHED_VPE1;
  93. break;
  94. case 2:
  95. action = GIC_IPI_EXT_INTR_RESCHED_VPE2;
  96. break;
  97. case 3:
  98. action = GIC_IPI_EXT_INTR_RESCHED_VPE3;
  99. break;
  100. }
  101. gic_send_ipi(action);
  102. }
  103. /*
  104. * FIXME: This isn't restricted to CMP
  105. * The SMVP kernel could use GIC interrupts if available
  106. */
  107. void cmp_send_ipi_single(int cpu, unsigned int action)
  108. {
  109. unsigned long flags;
  110. local_irq_save(flags);
  111. switch (action) {
  112. case SMP_CALL_FUNCTION:
  113. ipi_call_function(cpu);
  114. break;
  115. case SMP_RESCHEDULE_YOURSELF:
  116. ipi_resched(cpu);
  117. break;
  118. }
  119. local_irq_restore(flags);
  120. }
  121. static void cmp_send_ipi_mask(cpumask_t mask, unsigned int action)
  122. {
  123. unsigned int i;
  124. for_each_cpu_mask(i, mask)
  125. cmp_send_ipi_single(i, action);
  126. }
  127. static void cmp_init_secondary(void)
  128. {
  129. struct cpuinfo_mips *c = &current_cpu_data;
  130. /* Assume GIC is present */
  131. change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 |
  132. STATUSF_IP7);
  133. /* Enable per-cpu interrupts: platform specific */
  134. c->core = (read_c0_ebase() >> 1) & 0xff;
  135. #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
  136. c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
  137. #endif
  138. #ifdef CONFIG_MIPS_MT_SMTC
  139. c->tc_id = (read_c0_tcbind() >> TCBIND_CURTC_SHIFT) & TCBIND_CURTC;
  140. #endif
  141. }
  142. static void cmp_smp_finish(void)
  143. {
  144. pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
  145. /* CDFIXME: remove this? */
  146. write_c0_compare(read_c0_count() + (8 * mips_hpt_frequency / HZ));
  147. #ifdef CONFIG_MIPS_MT_FPAFF
  148. /* If we have an FPU, enroll ourselves in the FPU-full mask */
  149. if (cpu_has_fpu)
  150. cpu_set(smp_processor_id(), mt_fpu_cpumask);
  151. #endif /* CONFIG_MIPS_MT_FPAFF */
  152. local_irq_enable();
  153. }
  154. static void cmp_cpus_done(void)
  155. {
  156. pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
  157. }
  158. /*
  159. * Setup the PC, SP, and GP of a secondary processor and start it running
  160. * smp_bootstrap is the place to resume from
  161. * __KSTK_TOS(idle) is apparently the stack pointer
  162. * (unsigned long)idle->thread_info the gp
  163. */
  164. static void cmp_boot_secondary(int cpu, struct task_struct *idle)
  165. {
  166. struct thread_info *gp = task_thread_info(idle);
  167. unsigned long sp = __KSTK_TOS(idle);
  168. unsigned long pc = (unsigned long)&smp_bootstrap;
  169. unsigned long a0 = 0;
  170. pr_debug("SMPCMP: CPU%d: %s cpu %d\n", smp_processor_id(),
  171. __func__, cpu);
  172. #if 0
  173. /* Needed? */
  174. flush_icache_range((unsigned long)gp,
  175. (unsigned long)(gp + sizeof(struct thread_info)));
  176. #endif
  177. amon_cpu_start(cpu, pc, sp, gp, a0);
  178. }
  179. /*
  180. * Common setup before any secondaries are started
  181. */
  182. void __init cmp_smp_setup(void)
  183. {
  184. int i;
  185. int ncpu = 0;
  186. pr_debug("SMPCMP: CPU%d: %s\n", smp_processor_id(), __func__);
  187. #ifdef CONFIG_MIPS_MT_FPAFF
  188. /* If we have an FPU, enroll ourselves in the FPU-full mask */
  189. if (cpu_has_fpu)
  190. cpu_set(0, mt_fpu_cpumask);
  191. #endif /* CONFIG_MIPS_MT_FPAFF */
  192. for (i = 1; i < NR_CPUS; i++) {
  193. if (amon_cpu_avail(i)) {
  194. cpu_set(i, cpu_possible_map);
  195. __cpu_number_map[i] = ++ncpu;
  196. __cpu_logical_map[ncpu] = i;
  197. }
  198. }
  199. if (cpu_has_mipsmt) {
  200. unsigned int nvpe, mvpconf0 = read_c0_mvpconf0();
  201. nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
  202. smp_num_siblings = nvpe;
  203. }
  204. pr_info("Detected %i available secondary CPU(s)\n", ncpu);
  205. }
  206. void __init cmp_prepare_cpus(unsigned int max_cpus)
  207. {
  208. pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
  209. smp_processor_id(), __func__, max_cpus);
  210. /*
  211. * FIXME: some of these options are per-system, some per-core and
  212. * some per-cpu
  213. */
  214. mips_mt_set_cpuoptions();
  215. }
  216. struct plat_smp_ops cmp_smp_ops = {
  217. .send_ipi_single = cmp_send_ipi_single,
  218. .send_ipi_mask = cmp_send_ipi_mask,
  219. .init_secondary = cmp_init_secondary,
  220. .smp_finish = cmp_smp_finish,
  221. .cpus_done = cmp_cpus_done,
  222. .boot_secondary = cmp_boot_secondary,
  223. .smp_setup = cmp_smp_setup,
  224. .prepare_cpus = cmp_prepare_cpus,
  225. };