smp-cmp.c 6.3 KB

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