smp_32.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* smp.c: Sparc SMP support.
  3. *
  4. * Copyright (C) 1996 David S. Miller ([email protected])
  5. * Copyright (C) 1998 Jakub Jelinek ([email protected])
  6. * Copyright (C) 2004 Keith M Wesolowski ([email protected])
  7. */
  8. #include <asm/head.h>
  9. #include <linux/kernel.h>
  10. #include <linux/sched.h>
  11. #include <linux/threads.h>
  12. #include <linux/smp.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/kernel_stat.h>
  15. #include <linux/init.h>
  16. #include <linux/spinlock.h>
  17. #include <linux/mm.h>
  18. #include <linux/fs.h>
  19. #include <linux/seq_file.h>
  20. #include <linux/cache.h>
  21. #include <linux/delay.h>
  22. #include <linux/profile.h>
  23. #include <linux/cpu.h>
  24. #include <asm/ptrace.h>
  25. #include <linux/atomic.h>
  26. #include <asm/irq.h>
  27. #include <asm/page.h>
  28. #include <asm/oplib.h>
  29. #include <asm/cacheflush.h>
  30. #include <asm/tlbflush.h>
  31. #include <asm/cpudata.h>
  32. #include <asm/timer.h>
  33. #include <asm/leon.h>
  34. #include "kernel.h"
  35. #include "irq.h"
  36. volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
  37. cpumask_t smp_commenced_mask = CPU_MASK_NONE;
  38. const struct sparc32_ipi_ops *sparc32_ipi_ops;
  39. /* The only guaranteed locking primitive available on all Sparc
  40. * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
  41. * places the current byte at the effective address into dest_reg and
  42. * places 0xff there afterwards. Pretty lame locking primitive
  43. * compared to the Alpha and the Intel no? Most Sparcs have 'swap'
  44. * instruction which is much better...
  45. */
  46. void smp_store_cpu_info(int id)
  47. {
  48. int cpu_node;
  49. int mid;
  50. cpu_data(id).udelay_val = loops_per_jiffy;
  51. cpu_find_by_mid(id, &cpu_node);
  52. cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
  53. "clock-frequency", 0);
  54. cpu_data(id).prom_node = cpu_node;
  55. mid = cpu_get_hwmid(cpu_node);
  56. if (mid < 0) {
  57. printk(KERN_NOTICE "No MID found for CPU%d at node 0x%08x", id, cpu_node);
  58. mid = 0;
  59. }
  60. cpu_data(id).mid = mid;
  61. }
  62. void __init smp_cpus_done(unsigned int max_cpus)
  63. {
  64. unsigned long bogosum = 0;
  65. int cpu, num = 0;
  66. for_each_online_cpu(cpu) {
  67. num++;
  68. bogosum += cpu_data(cpu).udelay_val;
  69. }
  70. printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
  71. num, bogosum/(500000/HZ),
  72. (bogosum/(5000/HZ))%100);
  73. switch(sparc_cpu_model) {
  74. case sun4m:
  75. smp4m_smp_done();
  76. break;
  77. case sun4d:
  78. smp4d_smp_done();
  79. break;
  80. case sparc_leon:
  81. leon_smp_done();
  82. break;
  83. case sun4e:
  84. printk("SUN4E\n");
  85. BUG();
  86. break;
  87. case sun4u:
  88. printk("SUN4U\n");
  89. BUG();
  90. break;
  91. default:
  92. printk("UNKNOWN!\n");
  93. BUG();
  94. break;
  95. }
  96. }
  97. void cpu_panic(void)
  98. {
  99. printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
  100. panic("SMP bolixed\n");
  101. }
  102. struct linux_prom_registers smp_penguin_ctable = { 0 };
  103. void smp_send_reschedule(int cpu)
  104. {
  105. /*
  106. * CPU model dependent way of implementing IPI generation targeting
  107. * a single CPU. The trap handler needs only to do trap entry/return
  108. * to call schedule.
  109. */
  110. sparc32_ipi_ops->resched(cpu);
  111. }
  112. void smp_send_stop(void)
  113. {
  114. }
  115. void arch_send_call_function_single_ipi(int cpu)
  116. {
  117. /* trigger one IPI single call on one CPU */
  118. sparc32_ipi_ops->single(cpu);
  119. }
  120. void arch_send_call_function_ipi_mask(const struct cpumask *mask)
  121. {
  122. int cpu;
  123. /* trigger IPI mask call on each CPU */
  124. for_each_cpu(cpu, mask)
  125. sparc32_ipi_ops->mask_one(cpu);
  126. }
  127. void smp_resched_interrupt(void)
  128. {
  129. irq_enter();
  130. scheduler_ipi();
  131. local_cpu_data().irq_resched_count++;
  132. irq_exit();
  133. /* re-schedule routine called by interrupt return code. */
  134. }
  135. void smp_call_function_single_interrupt(void)
  136. {
  137. irq_enter();
  138. generic_smp_call_function_single_interrupt();
  139. local_cpu_data().irq_call_count++;
  140. irq_exit();
  141. }
  142. void smp_call_function_interrupt(void)
  143. {
  144. irq_enter();
  145. generic_smp_call_function_interrupt();
  146. local_cpu_data().irq_call_count++;
  147. irq_exit();
  148. }
  149. void __init smp_prepare_cpus(unsigned int max_cpus)
  150. {
  151. int i, cpuid, extra;
  152. printk("Entering SMP Mode...\n");
  153. extra = 0;
  154. for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) {
  155. if (cpuid >= NR_CPUS)
  156. extra++;
  157. }
  158. /* i = number of cpus */
  159. if (extra && max_cpus > i - extra)
  160. printk("Warning: NR_CPUS is too low to start all cpus\n");
  161. smp_store_cpu_info(boot_cpu_id);
  162. switch(sparc_cpu_model) {
  163. case sun4m:
  164. smp4m_boot_cpus();
  165. break;
  166. case sun4d:
  167. smp4d_boot_cpus();
  168. break;
  169. case sparc_leon:
  170. leon_boot_cpus();
  171. break;
  172. case sun4e:
  173. printk("SUN4E\n");
  174. BUG();
  175. break;
  176. case sun4u:
  177. printk("SUN4U\n");
  178. BUG();
  179. break;
  180. default:
  181. printk("UNKNOWN!\n");
  182. BUG();
  183. break;
  184. }
  185. }
  186. /* Set this up early so that things like the scheduler can init
  187. * properly. We use the same cpu mask for both the present and
  188. * possible cpu map.
  189. */
  190. void __init smp_setup_cpu_possible_map(void)
  191. {
  192. int instance, mid;
  193. instance = 0;
  194. while (!cpu_find_by_instance(instance, NULL, &mid)) {
  195. if (mid < NR_CPUS) {
  196. set_cpu_possible(mid, true);
  197. set_cpu_present(mid, true);
  198. }
  199. instance++;
  200. }
  201. }
  202. void __init smp_prepare_boot_cpu(void)
  203. {
  204. int cpuid = hard_smp_processor_id();
  205. if (cpuid >= NR_CPUS) {
  206. prom_printf("Serious problem, boot cpu id >= NR_CPUS\n");
  207. prom_halt();
  208. }
  209. if (cpuid != 0)
  210. printk("boot cpu id != 0, this could work but is untested\n");
  211. current_thread_info()->cpu = cpuid;
  212. set_cpu_online(cpuid, true);
  213. set_cpu_possible(cpuid, true);
  214. }
  215. int __cpu_up(unsigned int cpu, struct task_struct *tidle)
  216. {
  217. int ret=0;
  218. switch(sparc_cpu_model) {
  219. case sun4m:
  220. ret = smp4m_boot_one_cpu(cpu, tidle);
  221. break;
  222. case sun4d:
  223. ret = smp4d_boot_one_cpu(cpu, tidle);
  224. break;
  225. case sparc_leon:
  226. ret = leon_boot_one_cpu(cpu, tidle);
  227. break;
  228. case sun4e:
  229. printk("SUN4E\n");
  230. BUG();
  231. break;
  232. case sun4u:
  233. printk("SUN4U\n");
  234. BUG();
  235. break;
  236. default:
  237. printk("UNKNOWN!\n");
  238. BUG();
  239. break;
  240. }
  241. if (!ret) {
  242. cpumask_set_cpu(cpu, &smp_commenced_mask);
  243. while (!cpu_online(cpu))
  244. mb();
  245. }
  246. return ret;
  247. }
  248. static void arch_cpu_pre_starting(void *arg)
  249. {
  250. local_ops->cache_all();
  251. local_ops->tlb_all();
  252. switch(sparc_cpu_model) {
  253. case sun4m:
  254. sun4m_cpu_pre_starting(arg);
  255. break;
  256. case sun4d:
  257. sun4d_cpu_pre_starting(arg);
  258. break;
  259. case sparc_leon:
  260. leon_cpu_pre_starting(arg);
  261. break;
  262. default:
  263. BUG();
  264. }
  265. }
  266. static void arch_cpu_pre_online(void *arg)
  267. {
  268. unsigned int cpuid = hard_smp_processor_id();
  269. register_percpu_ce(cpuid);
  270. calibrate_delay();
  271. smp_store_cpu_info(cpuid);
  272. local_ops->cache_all();
  273. local_ops->tlb_all();
  274. switch(sparc_cpu_model) {
  275. case sun4m:
  276. sun4m_cpu_pre_online(arg);
  277. break;
  278. case sun4d:
  279. sun4d_cpu_pre_online(arg);
  280. break;
  281. case sparc_leon:
  282. leon_cpu_pre_online(arg);
  283. break;
  284. default:
  285. BUG();
  286. }
  287. }
  288. static void sparc_start_secondary(void *arg)
  289. {
  290. unsigned int cpu;
  291. /*
  292. * SMP booting is extremely fragile in some architectures. So run
  293. * the cpu initialization code first before anything else.
  294. */
  295. arch_cpu_pre_starting(arg);
  296. cpu = smp_processor_id();
  297. notify_cpu_starting(cpu);
  298. arch_cpu_pre_online(arg);
  299. /* Set the CPU in the cpu_online_mask */
  300. set_cpu_online(cpu, true);
  301. /* Enable local interrupts now */
  302. local_irq_enable();
  303. wmb();
  304. cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
  305. /* We should never reach here! */
  306. BUG();
  307. }
  308. void smp_callin(void)
  309. {
  310. sparc_start_secondary(NULL);
  311. }
  312. void smp_bogo(struct seq_file *m)
  313. {
  314. int i;
  315. for_each_online_cpu(i) {
  316. seq_printf(m,
  317. "Cpu%dBogo\t: %lu.%02lu\n",
  318. i,
  319. cpu_data(i).udelay_val/(500000/HZ),
  320. (cpu_data(i).udelay_val/(5000/HZ))%100);
  321. }
  322. }
  323. void smp_info(struct seq_file *m)
  324. {
  325. int i;
  326. seq_printf(m, "State:\n");
  327. for_each_online_cpu(i)
  328. seq_printf(m, "CPU%d\t\t: online\n", i);
  329. }