smp.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. #include <linux/config.h>
  2. #include <linux/init.h>
  3. #include <linux/spinlock.h>
  4. #include <linux/threads.h>
  5. #include <linux/time.h>
  6. #include <linux/timex.h>
  7. #include <linux/sched.h>
  8. #include <linux/cache.h>
  9. #include <asm/atomic.h>
  10. #include <asm/processor.h>
  11. #include <asm/system.h>
  12. #include <asm/hardirq.h>
  13. #include <asm/softirq.h>
  14. #include <asm/mmu_context.h>
  15. #include <asm/irq.h>
  16. #ifdef CONFIG_SGI_IP27
  17. #include <asm/sn/arch.h>
  18. #include <asm/sn/intr.h>
  19. #include <asm/sn/addrs.h>
  20. #include <asm/sn/agent.h>
  21. #include <asm/sn/sn0/ip27.h>
  22. #define DORESCHED 0xab
  23. #define DOCALL 0xbc
  24. static void sendintr(int destid, unsigned char status)
  25. {
  26. int irq;
  27. #if (CPUS_PER_NODE == 2)
  28. switch (status) {
  29. case DORESCHED: irq = CPU_RESCHED_A_IRQ; break;
  30. case DOCALL: irq = CPU_CALL_A_IRQ; break;
  31. default: panic("sendintr");
  32. }
  33. irq += cputoslice(destid);
  34. /*
  35.  * Convert the compact hub number to the NASID to get the correct
  36.  * part of the address space.  Then set the interrupt bit associated
  37.  * with the CPU we want to send the interrupt to.
  38.  */
  39. REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)),
  40. FAST_IRQ_TO_LEVEL(irq));
  41. #else
  42. << Bomb!  Must redefine this for more than 2 CPUS. >>
  43. #endif
  44. }
  45. #endif /* CONFIG_SGI_IP27 */
  46. /* The 'big kernel lock' */
  47. spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
  48. int smp_threads_ready; /* Not used */
  49. atomic_t smp_commenced = ATOMIC_INIT(0);
  50. struct cpuinfo_mips cpu_data[NR_CPUS];
  51. int smp_num_cpus = 1; /* Number that came online.  */
  52. int __cpu_number_map[NR_CPUS];
  53. int __cpu_logical_map[NR_CPUS];
  54. cycles_t cacheflush_time;
  55. static void smp_tune_scheduling (void)
  56. {
  57. }
  58. void __init smp_boot_cpus(void)
  59. {
  60. extern void allowboot(void);
  61. init_new_context(current, &init_mm);
  62. current->processor = 0;
  63. init_idle();
  64. smp_tune_scheduling();
  65. allowboot();
  66. }
  67. void __init smp_commence(void)
  68. {
  69. wmb();
  70. atomic_set(&smp_commenced,1);
  71. }
  72. static void stop_this_cpu(void *dummy)
  73. {
  74. /*
  75.  * Remove this CPU
  76.  */
  77. for (;;);
  78. }
  79. void smp_send_stop(void)
  80. {
  81. smp_call_function(stop_this_cpu, NULL, 1, 0);
  82. smp_num_cpus = 1;
  83. }
  84. /*
  85.  * this function sends a 'reschedule' IPI to another CPU.
  86.  * it goes straight through and wastes no time serializing
  87.  * anything. Worst case is that we lose a reschedule ...
  88.  */
  89. void smp_send_reschedule(int cpu)
  90. {
  91. sendintr(cpu, DORESCHED);
  92. }
  93. /* Not really SMP stuff ... */
  94. int setup_profiling_timer(unsigned int multiplier)
  95. {
  96. return 0;
  97. }
  98. /*
  99.  * Run a function on all other CPUs.
  100.  *  <func>      The function to run. This must be fast and non-blocking.
  101.  *  <info>      An arbitrary pointer to pass to the function.
  102.  *  <retry>     If true, keep retrying until ready.
  103.  *  <wait>      If true, wait until function has completed on other CPUs.
  104.  *  [RETURNS]   0 on success, else a negative status code.
  105.  *
  106.  * Does not return until remote CPUs are nearly ready to execute <func>
  107.  * or are or have executed.
  108.  */
  109. static volatile struct call_data_struct {
  110. void (*func) (void *info);
  111. void *info;
  112. atomic_t started;
  113. atomic_t finished;
  114. int wait;
  115. } *call_data;
  116. int smp_call_function (void (*func) (void *info), void *info, int retry, 
  117. int wait)
  118. {
  119. struct call_data_struct data;
  120. int i, cpus = smp_num_cpus-1;
  121. static spinlock_t lock = SPIN_LOCK_UNLOCKED;
  122. if (cpus == 0)
  123. return 0;
  124. data.func = func;
  125. data.info = info;
  126. atomic_set(&data.started, 0);
  127. data.wait = wait;
  128. if (wait)
  129. atomic_set(&data.finished, 0);
  130. spin_lock_bh(&lock);
  131. call_data = &data;
  132. /* Send a message to all other CPUs and wait for them to respond */
  133. for (i = 0; i < smp_num_cpus; i++)
  134. if (smp_processor_id() != i)
  135. sendintr(i, DOCALL);
  136. /* Wait for response */
  137. /* FIXME: lock-up detection, backtrace on lock-up */
  138. while (atomic_read(&data.started) != cpus)
  139. barrier();
  140. if (wait)
  141. while (atomic_read(&data.finished) != cpus)
  142. barrier();
  143. spin_unlock_bh(&lock);
  144. return 0;
  145. }
  146. extern void smp_call_function_interrupt(int irq, void *d, struct pt_regs *r)
  147. {
  148. void (*func) (void *info) = call_data->func;
  149. void *info = call_data->info;
  150. int wait = call_data->wait;
  151. /*
  152.  * Notify initiating CPU that I've grabbed the data and am
  153.  * about to execute the function.
  154.  */
  155. atomic_inc(&call_data->started);
  156. /*
  157.  * At this point the info structure may be out of scope unless wait==1.
  158.  */
  159. (*func)(info);
  160. if (wait)
  161. atomic_inc(&call_data->finished);
  162. }
  163. static void flush_tlb_all_ipi(void *info)
  164. {
  165. _flush_tlb_all();
  166. }
  167. void flush_tlb_all(void)
  168. {
  169. smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
  170. _flush_tlb_all();
  171. }
  172. static void flush_tlb_mm_ipi(void *mm)
  173. {
  174. _flush_tlb_mm((struct mm_struct *)mm);
  175. }
  176. /*
  177.  * The following tlb flush calls are invoked when old translations are 
  178.  * being torn down, or pte attributes are changing. For single threaded
  179.  * address spaces, a new context is obtained on the current cpu, and tlb
  180.  * context on other cpus are invalidated to force a new context allocation
  181.  * at switch_mm time, should the mm ever be used on other cpus. For 
  182.  * multithreaded address spaces, intercpu interrupts have to be sent.
  183.  * Another case where intercpu interrupts are required is when the target
  184.  * mm might be active on another cpu (eg debuggers doing the flushes on
  185.  * behalf of debugees, kswapd stealing pages from another process etc).
  186.  * Kanoj 07/00.
  187.  */
  188. void flush_tlb_mm(struct mm_struct *mm)
  189. {
  190. if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
  191. smp_call_function(flush_tlb_mm_ipi, (void *)mm, 1, 1);
  192. } else {
  193. int i;
  194. for (i = 0; i < smp_num_cpus; i++)
  195. if (smp_processor_id() != i)
  196. CPU_CONTEXT(i, mm) = 0;
  197. }
  198. _flush_tlb_mm(mm);
  199. }
  200. struct flush_tlb_data {
  201. struct mm_struct *mm;
  202. struct vm_area_struct *vma;
  203. unsigned long addr1;
  204. unsigned long addr2;
  205. };
  206. static void flush_tlb_range_ipi(void *info)
  207. {
  208. struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
  209. _flush_tlb_range(fd->mm, fd->addr1, fd->addr2);
  210. }
  211. void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
  212. {
  213. if ((atomic_read(&mm->mm_users) != 1) || (current->mm != mm)) {
  214. struct flush_tlb_data fd;
  215. fd.mm = mm;
  216. fd.addr1 = start;
  217. fd.addr2 = end;
  218. smp_call_function(flush_tlb_range_ipi, (void *)&fd, 1, 1);
  219. } else {
  220. int i;
  221. for (i = 0; i < smp_num_cpus; i++)
  222. if (smp_processor_id() != i)
  223. CPU_CONTEXT(i, mm) = 0;
  224. }
  225. _flush_tlb_range(mm, start, end);
  226. }
  227. static void flush_tlb_page_ipi(void *info)
  228. {
  229. struct flush_tlb_data *fd = (struct flush_tlb_data *)info;
  230. _flush_tlb_page(fd->vma, fd->addr1);
  231. }
  232. void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  233. {
  234. if ((atomic_read(&vma->vm_mm->mm_users) != 1) || (current->mm != vma->vm_mm)) {
  235. struct flush_tlb_data fd;
  236. fd.vma = vma;
  237. fd.addr1 = page;
  238. smp_call_function(flush_tlb_page_ipi, (void *)&fd, 1, 1);
  239. } else {
  240. int i;
  241. for (i = 0; i < smp_num_cpus; i++)
  242. if (smp_processor_id() != i)
  243. CPU_CONTEXT(i, vma->vm_mm) = 0;
  244. }
  245. _flush_tlb_page(vma, page);
  246. }