smp.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This program is free software; you can redistribute it and/or
  3.  * modify it under the terms of the GNU General Public License
  4.  * as published by the Free Software Foundation; either version 2
  5.  * of the License, or (at your option) any later version.
  6.  *
  7.  * This program is distributed in the hope that it will be useful,
  8.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  * GNU General Public License for more details.
  11.  *
  12.  * You should have received a copy of the GNU General Public License
  13.  * along with this program; if not, write to the Free Software
  14.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  15.  *
  16.  * Copyright (C) 2000, 2001 Kanoj Sarcar
  17.  * Copyright (C) 2000, 2001 Ralf Baechle
  18.  * Copyright (C) 2000, 2001 Silicon Graphics, Inc.
  19.  * Copyright (C) 2000, 2001 Broadcom Corporation
  20.  */
  21. #include <linux/config.h>
  22. #include <linux/cache.h>
  23. #include <linux/delay.h>
  24. #include <linux/init.h>
  25. #include <linux/interrupt.h>
  26. #include <linux/spinlock.h>
  27. #include <linux/threads.h>
  28. #include <linux/module.h>
  29. #include <linux/time.h>
  30. #include <linux/timex.h>
  31. #include <linux/sched.h>
  32. #include <asm/atomic.h>
  33. #include <asm/cpu.h>
  34. #include <asm/processor.h>
  35. #include <asm/system.h>
  36. #include <asm/hardirq.h>
  37. #include <asm/softirq.h>
  38. #include <asm/mmu_context.h>
  39. #include <asm/smp.h>
  40. /* The 'big kernel lock' */
  41. spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
  42. int smp_threads_ready; /* Not used */
  43. atomic_t smp_commenced = ATOMIC_INIT(0);
  44. struct cpuinfo_mips cpu_data[NR_CPUS];
  45. // static atomic_t cpus_booted = ATOMIC_INIT(0);
  46. atomic_t cpus_booted = ATOMIC_INIT(0);
  47. int smp_num_cpus = 1; /* Number that came online.  */
  48. cpumask_t cpu_online_map; /* Bitmask of currently online CPUs */
  49. int __cpu_number_map[NR_CPUS];
  50. int __cpu_logical_map[NR_CPUS];
  51. cycles_t cacheflush_time;
  52. /* These are defined by the board-specific code. */
  53. /*
  54.  * Cause the function described by call_data to be executed on the passed
  55.  * cpu.  When the function has finished, increment the finished field of
  56.  * call_data.
  57.  */
  58. void core_send_ipi(int cpu, unsigned int action);
  59. /*
  60.  * Clear all undefined state in the cpu, set up sp and gp to the passed
  61.  * values, and kick the cpu into smp_bootstrap();
  62.  */
  63. void prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp);
  64. /*
  65.  *  After we've done initial boot, this function is called to allow the
  66.  *  board code to clean up state, if needed
  67.  */
  68. void prom_init_secondary(void);
  69. /*
  70.  * Do whatever setup needs to be done for SMP at the board level.  Return
  71.  * the number of cpus in the system, including this one
  72.  */
  73. int prom_setup_smp(void);
  74. void prom_smp_finish(void);
  75. static void smp_tune_scheduling(void)
  76. {
  77. }
  78. void __init smp_callin(void)
  79. {
  80. #if 0
  81. calibrate_delay();
  82. smp_store_cpu_info(cpuid);
  83. #endif
  84. }
  85. #ifndef CONFIG_SGI_IP27
  86. /*
  87.  * Hook for doing final board-specific setup after the generic smp setup
  88.  * is done
  89.  */
  90. asmlinkage void start_secondary(void)
  91. {
  92. unsigned int cpu = smp_processor_id();
  93. prom_init_secondary();
  94. per_cpu_trap_init();
  95. /*
  96.  * XXX parity protection should be folded in here when it's converted
  97.  * to an option instead of something based on .cputype
  98.  */
  99. pgd_current[cpu] = init_mm.pgd;
  100. cpu_data[cpu].udelay_val = loops_per_jiffy;
  101. prom_smp_finish();
  102. printk("Slave cpu booted successfullyn");
  103. CPUMASK_SETB(cpu_online_map, cpu);
  104. atomic_inc(&cpus_booted);
  105. while (!atomic_read(&smp_commenced));
  106. cpu_idle();
  107. }
  108. #endif /* CONFIG_SGI_IP27 */
  109. void __init smp_commence(void)
  110. {
  111. wmb();
  112. atomic_set(&smp_commenced, 1);
  113. }
  114. /*
  115.  * this function sends a 'reschedule' IPI to another CPU.
  116.  * it goes straight through and wastes no time serializing
  117.  * anything. Worst case is that we lose a reschedule ...
  118.  */
  119. void smp_send_reschedule(int cpu)
  120. {
  121. core_send_ipi(cpu, SMP_RESCHEDULE_YOURSELF);
  122. }
  123. static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
  124. struct call_data_struct *call_data;
  125. /*
  126.  * Run a function on all other CPUs.
  127.  *  <func>      The function to run. This must be fast and non-blocking.
  128.  *  <info>      An arbitrary pointer to pass to the function.
  129.  *  <retry>     If true, keep retrying until ready.
  130.  *  <wait>      If true, wait until function has completed on other CPUs.
  131.  *  [RETURNS]   0 on success, else a negative status code.
  132.  *
  133.  * Does not return until remote CPUs are nearly ready to execute <func>
  134.  * or are or have executed.
  135.  */
  136. int smp_call_function (void (*func) (void *info), void *info, int retry,
  137. int wait)
  138. {
  139. struct call_data_struct data;
  140. int i, cpus = smp_num_cpus - 1;
  141. int cpu = smp_processor_id();
  142. if (!cpus)
  143. return 0;
  144. data.func = func;
  145. data.info = info;
  146. atomic_set(&data.started, 0);
  147. data.wait = wait;
  148. if (wait)
  149. atomic_set(&data.finished, 0);
  150. spin_lock(&call_lock);
  151. call_data = &data;
  152. /* Send a message to all other CPUs and wait for them to respond */
  153. for (i = 0; i < smp_num_cpus; i++)
  154. if (i != cpu)
  155. core_send_ipi(i, SMP_CALL_FUNCTION);
  156. /* Wait for response */
  157. /* FIXME: lock-up detection, backtrace on lock-up */
  158. while (atomic_read(&data.started) != cpus)
  159. barrier();
  160. if (wait)
  161. while (atomic_read(&data.finished) != cpus)
  162. barrier();
  163. spin_unlock(&call_lock);
  164. return 0;
  165. }
  166. void smp_call_function_interrupt(void)
  167. {
  168. void (*func) (void *info) = call_data->func;
  169. void *info = call_data->info;
  170. int wait = call_data->wait;
  171. int cpu = smp_processor_id();
  172. irq_enter(cpu, 0); /* XXX choose an irq number? */
  173. /*
  174.  * Notify initiating CPU that I've grabbed the data and am
  175.  * about to execute the function.
  176.  */
  177. mb();
  178. atomic_inc(&call_data->started);
  179. /*
  180.  * At this point the info structure may be out of scope unless wait==1.
  181.  */
  182. (*func)(info);
  183. if (wait) {
  184. mb();
  185. atomic_inc(&call_data->finished);
  186. }
  187. irq_exit(cpu, 0); /* XXX choose an irq number? */
  188. }
  189. static void stop_this_cpu(void *dummy)
  190. {
  191. /*
  192.  * Remove this CPU:
  193.  */
  194. clear_bit(smp_processor_id(), &cpu_online_map);
  195. /* May need to service _machine_restart IPI */
  196. __sti();
  197. /* XXXKW wait if available? */
  198. for (;;);
  199. }
  200. void smp_send_stop(void)
  201. {
  202. smp_call_function(stop_this_cpu, NULL, 1, 0);
  203. /*
  204.  * Fix me: this prevents future IPIs, for example that would
  205.  * cause a restart to happen on CPU0.
  206.  */
  207. smp_num_cpus = 1;
  208. }
  209. /* Not really SMP stuff ... */
  210. int setup_profiling_timer(unsigned int multiplier)
  211. {
  212. return 0;
  213. }
  214. static void flush_tlb_all_ipi(void *info)
  215. {
  216. local_flush_tlb_all();
  217. }
  218. void flush_tlb_all(void)
  219. {
  220. smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
  221. local_flush_tlb_all();
  222. }
  223. static void flush_tlb_mm_ipi(void *mm)
  224. {
  225. local_flush_tlb_mm((struct mm_struct *)mm);
  226. }
  227. /*
  228.  * The following tlb flush calls are invoked when old translations are
  229.  * being torn down, or pte attributes are changing. For single threaded
  230.  * address spaces, a new context is obtained on the current cpu, and tlb
  231.  * context on other cpus are invalidated to force a new context allocation
  232.  * at switch_mm time, should the mm ever be used on other cpus. For
  233.  * multithreaded address spaces, intercpu interrupts have to be sent.
  234.  * Another case where intercpu interrupts are required is when the target
  235.  * mm might be active on another cpu (eg debuggers doing the flushes on
  236.  * behalf of debugees, kswapd stealing pages from another process etc).
  237.  * Kanoj 07/00.
  238.  */
  239. void flush_tlb_mm(struct mm_struct *mm)
  240. {
  241. if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
  242. smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
  243. } else {
  244. int i;
  245. for (i = 0; i < smp_num_cpus; i++)
  246. if (smp_processor_id() != i)
  247. CPU_CONTEXT(i, mm) = 0;
  248. }
  249. local_flush_tlb_mm(mm);
  250. }
  251. struct flush_tlb_data {
  252. struct mm_struct *mm;
  253. struct vm_area_struct *vma;
  254. unsigned long addr1;
  255. unsigned long addr2;
  256. };
  257. static void flush_tlb_range_ipi(void *info)
  258. {
  259. struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
  260. local_flush_tlb_range(fd->mm, fd->addr1, fd->addr2);
  261. }
  262. void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
  263. {
  264. if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
  265. struct flush_tlb_data fd;
  266. fd.mm = mm;
  267. fd.addr1 = start;
  268. fd.addr2 = end;
  269. smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
  270. } else {
  271. int i;
  272. for (i = 0; i < smp_num_cpus; i++)
  273. if (smp_processor_id() != i)
  274. CPU_CONTEXT(i, mm) = 0;
  275. }
  276. local_flush_tlb_range(mm, start, end);
  277. }
  278. static void flush_tlb_page_ipi(void *info)
  279. {
  280. struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
  281. local_flush_tlb_page(fd->vma, fd->addr1);
  282. }
  283. void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  284. {
  285. if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) {
  286. struct flush_tlb_data fd;
  287. fd.vma = vma;
  288. fd.addr1 = page;
  289. smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
  290. } else {
  291. int i;
  292. for (i = 0; i < smp_num_cpus; i++)
  293. if (smp_processor_id() != i)
  294. CPU_CONTEXT(i, vma->vm_mm) = 0;
  295. }
  296. local_flush_tlb_page(vma, page);
  297. }
  298. EXPORT_SYMBOL(smp_num_cpus);
  299. EXPORT_SYMBOL(flush_tlb_page);
  300. EXPORT_SYMBOL(cpu_data);
  301. EXPORT_SYMBOL(synchronize_irq);
  302. EXPORT_SYMBOL(kernel_flag);
  303. EXPORT_SYMBOL(__global_sti);
  304. EXPORT_SYMBOL(__global_cli);
  305. EXPORT_SYMBOL(__global_save_flags);
  306. EXPORT_SYMBOL(__global_restore_flags);