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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* sun4d_smp.c: Sparc SS1000/SC2000 SMP support.
  2.  *
  3.  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  4.  *
  5.  * Based on sun4m's smp.c, which is:
  6.  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  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/smp_lock.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/kernel_stat.h>
  16. #include <linux/init.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/mm.h>
  19. #include <asm/ptrace.h>
  20. #include <asm/atomic.h>
  21. #include <asm/delay.h>
  22. #include <asm/irq.h>
  23. #include <asm/page.h>
  24. #include <asm/pgalloc.h>
  25. #include <asm/pgtable.h>
  26. #include <asm/oplib.h>
  27. #include <asm/hardirq.h>
  28. #include <asm/softirq.h>
  29. #include <asm/sbus.h>
  30. #include <asm/sbi.h>
  31. #define __KERNEL_SYSCALLS__
  32. #include <linux/unistd.h>
  33. #define IRQ_CROSS_CALL 15
  34. extern ctxd_t *srmmu_ctx_table_phys;
  35. extern int linux_num_cpus;
  36. extern void calibrate_delay(void);
  37. extern struct task_struct *current_set[NR_CPUS];
  38. extern volatile int smp_processors_ready;
  39. extern unsigned long cpu_present_map;
  40. extern int smp_num_cpus;
  41. static int smp_highest_cpu;
  42. extern int smp_threads_ready;
  43. extern unsigned char mid_xlate[NR_CPUS];
  44. extern volatile unsigned long cpu_callin_map[NR_CPUS];
  45. extern unsigned long smp_proc_in_lock[NR_CPUS];
  46. extern struct cpuinfo_sparc cpu_data[NR_CPUS];
  47. extern unsigned long cpu_offset[NR_CPUS];
  48. extern unsigned char boot_cpu_id;
  49. extern int smp_activated;
  50. extern volatile int __cpu_number_map[NR_CPUS];
  51. extern volatile int __cpu_logical_map[NR_CPUS];
  52. extern volatile unsigned long ipi_count;
  53. extern volatile int smp_process_available;
  54. extern volatile int smp_commenced;
  55. extern int __smp4d_processor_id(void);
  56. extern unsigned long totalram_pages;
  57. /* #define SMP_DEBUG */
  58. #ifdef SMP_DEBUG
  59. #define SMP_PRINTK(x) printk x
  60. #else
  61. #define SMP_PRINTK(x)
  62. #endif
  63. static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
  64. {
  65. __asm__ __volatile__("swap [%1], %0nt" :
  66.      "=&r" (val), "=&r" (ptr) :
  67.      "0" (val), "1" (ptr));
  68. return val;
  69. }
  70. static void smp_setup_percpu_timer(void);
  71. extern void cpu_probe(void);
  72. extern void sun4d_distribute_irqs(void);
  73. void __init smp4d_callin(void)
  74. {
  75. int cpuid = hard_smp4d_processor_id();
  76. extern spinlock_t sun4d_imsk_lock;
  77. unsigned long flags;
  78. /* Show we are alive */
  79. cpu_leds[cpuid] = 0x6;
  80. show_leds(cpuid);
  81. /* Enable level15 interrupt, disable level14 interrupt for now */
  82. cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
  83. local_flush_cache_all();
  84. local_flush_tlb_all();
  85. /*
  86.  * Unblock the master CPU _only_ when the scheduler state
  87.  * of all secondary CPUs will be up-to-date, so after
  88.  * the SMP initialization the master will be just allowed
  89.  * to call the scheduler code.
  90.  */
  91. init_idle();
  92. /* Get our local ticker going. */
  93. smp_setup_percpu_timer();
  94. calibrate_delay();
  95. smp_store_cpu_info(cpuid);
  96. local_flush_cache_all();
  97. local_flush_tlb_all();
  98. /* Allow master to continue. */
  99. swap((unsigned long *)&cpu_callin_map[cpuid], 1);
  100. local_flush_cache_all();
  101. local_flush_tlb_all();
  102. cpu_probe();
  103. while((unsigned long)current_set[cpuid] < PAGE_OFFSET)
  104. barrier();
  105. while(current_set[cpuid]->processor != cpuid)
  106. barrier();
  107. /* Fix idle thread fields. */
  108. __asm__ __volatile__("ld [%0], %%g6nt"
  109.      "sta %%g6, [%%g0] %1nt"
  110.      : : "r" (&current_set[cpuid]), "i" (ASI_M_VIKING_TMP2)
  111.      : "memory" /* paranoid */);
  112. cpu_leds[cpuid] = 0x9;
  113. show_leds(cpuid);
  114. /* Attach to the address space of init_task. */
  115. atomic_inc(&init_mm.mm_count);
  116. current->active_mm = &init_mm;
  117. local_flush_cache_all();
  118. local_flush_tlb_all();
  119. __sti(); /* We don't allow PIL 14 yet */
  120. while(!smp_commenced)
  121. barrier();
  122. spin_lock_irqsave(&sun4d_imsk_lock, flags);
  123. cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
  124. spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
  125. }
  126. extern int cpu_idle(void *unused);
  127. extern void init_IRQ(void);
  128. extern void cpu_panic(void);
  129. extern int start_secondary(void *unused);
  130. /*
  131.  * Cycle through the processors asking the PROM to start each one.
  132.  */
  133.  
  134. extern struct prom_cpuinfo linux_cpus[NR_CPUS];
  135. extern struct linux_prom_registers smp_penguin_ctable;
  136. extern unsigned long trapbase_cpu1[];
  137. extern unsigned long trapbase_cpu2[];
  138. extern unsigned long trapbase_cpu3[];
  139. void __init smp4d_boot_cpus(void)
  140. {
  141. int cpucount = 0;
  142. int i = 0;
  143. printk("Entering SMP Mode...n");
  144. for (i = 0; i < NR_CPUS; i++)
  145. cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
  146. if (boot_cpu_id)
  147. current_set[0] = NULL;
  148. __sti();
  149. cpu_present_map = 0;
  150. for(i=0; i < linux_num_cpus; i++)
  151. cpu_present_map |= (1<<linux_cpus[i].mid);
  152. SMP_PRINTK(("cpu_present_map %08lxn", cpu_present_map));
  153. for(i=0; i < NR_CPUS; i++)
  154. __cpu_number_map[i] = -1;
  155. for(i=0; i < NR_CPUS; i++)
  156. __cpu_logical_map[i] = -1;
  157. for(i=0; i < NR_CPUS; i++)
  158. mid_xlate[i] = i;
  159. __cpu_number_map[boot_cpu_id] = 0;
  160. __cpu_logical_map[0] = boot_cpu_id;
  161. current->processor = boot_cpu_id;
  162. smp_store_cpu_info(boot_cpu_id);
  163. smp_setup_percpu_timer();
  164. init_idle();
  165. local_flush_cache_all();
  166. if(linux_num_cpus == 1)
  167. return;  /* Not an MP box. */
  168. SMP_PRINTK(("Iterating over CPUsn"));
  169. for(i = 0; i < NR_CPUS; i++) {
  170. if(i == boot_cpu_id)
  171. continue;
  172. if(cpu_present_map & (1 << i)) {
  173. extern unsigned long sun4d_cpu_startup;
  174. unsigned long *entry = &sun4d_cpu_startup;
  175. struct task_struct *p;
  176. int timeout;
  177. int no;
  178. /* Cook up an idler for this guy. */
  179. kernel_thread(start_secondary, NULL, CLONE_PID);
  180. cpucount++;
  181. p = init_task.prev_task;
  182. init_tasks[i] = p;
  183. p->processor = i;
  184. p->cpus_runnable = 1 << i; /* we schedule the first task manually */
  185. current_set[i] = p;
  186. del_from_runqueue(p);
  187. unhash_process(p);
  188. for (no = 0; no < linux_num_cpus; no++)
  189. if (linux_cpus[no].mid == i)
  190. break;
  191. /*
  192.  * Initialize the contexts table
  193.  * Since the call to prom_startcpu() trashes the structure,
  194.  * we need to re-initialize it for each cpu
  195.  */
  196. smp_penguin_ctable.which_io = 0;
  197. smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
  198. smp_penguin_ctable.reg_size = 0;
  199. /* whirrr, whirrr, whirrrrrrrrr... */
  200. SMP_PRINTK(("Starting CPU %d at %p task %d node %08xn", i, entry, cpucount, linux_cpus[no].prom_node));
  201. local_flush_cache_all();
  202. prom_startcpu(linux_cpus[no].prom_node,
  203.       &smp_penguin_ctable, 0, (char *)entry);
  204.       
  205. SMP_PRINTK(("prom_startcpu returned :)n"));
  206. /* wheee... it's going... */
  207. for(timeout = 0; timeout < 10000; timeout++) {
  208. if(cpu_callin_map[i])
  209. break;
  210. udelay(200);
  211. }
  212. if(cpu_callin_map[i]) {
  213. /* Another "Red Snapper". */
  214. __cpu_number_map[i] = cpucount;
  215. __cpu_logical_map[cpucount] = i;
  216. } else {
  217. cpucount--;
  218. printk("Processor %d is stuck.n", i);
  219. }
  220. }
  221. if(!(cpu_callin_map[i])) {
  222. cpu_present_map &= ~(1 << i);
  223. __cpu_number_map[i] = -1;
  224. }
  225. }
  226. local_flush_cache_all();
  227. if(cpucount == 0) {
  228. printk("Error: only one Processor found.n");
  229. cpu_present_map = (1 << hard_smp4d_processor_id());
  230. } else {
  231. unsigned long bogosum = 0;
  232. for(i = 0; i < NR_CPUS; i++) {
  233. if(cpu_present_map & (1 << i)) {
  234. bogosum += cpu_data[i].udelay_val;
  235. smp_highest_cpu = i;
  236. }
  237. }
  238. SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).n", cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100));
  239. printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).n",
  240.        cpucount + 1,
  241.        bogosum/(500000/HZ),
  242.        (bogosum/(5000/HZ))%100);
  243. smp_activated = 1;
  244. smp_num_cpus = cpucount + 1;
  245. }
  246. /* Free unneeded trap tables */
  247. ClearPageReserved(virt_to_page(trapbase_cpu1));
  248. set_page_count(virt_to_page(trapbase_cpu1), 1);
  249. free_page((unsigned long)trapbase_cpu1);
  250. totalram_pages++;
  251. num_physpages++;
  252. ClearPageReserved(virt_to_page(trapbase_cpu2));
  253. set_page_count(virt_to_page(trapbase_cpu2), 1);
  254. free_page((unsigned long)trapbase_cpu2);
  255. totalram_pages++;
  256. num_physpages++;
  257. ClearPageReserved(virt_to_page(trapbase_cpu3));
  258. set_page_count(virt_to_page(trapbase_cpu3), 1);
  259. free_page((unsigned long)trapbase_cpu3);
  260. totalram_pages++;
  261. num_physpages++;
  262. /* Ok, they are spinning and ready to go. */
  263. smp_processors_ready = 1;
  264. sun4d_distribute_irqs();
  265. }
  266. static struct smp_funcall {
  267. smpfunc_t func;
  268. unsigned long arg1;
  269. unsigned long arg2;
  270. unsigned long arg3;
  271. unsigned long arg4;
  272. unsigned long arg5;
  273. unsigned char processors_in[NR_CPUS];  /* Set when ipi entered. */
  274. unsigned char processors_out[NR_CPUS]; /* Set when ipi exited. */
  275. } ccall_info __attribute__((aligned(8)));
  276. static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
  277. /* Cross calls must be serialized, at least currently. */
  278. void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
  279.     unsigned long arg3, unsigned long arg4, unsigned long arg5)
  280. {
  281. if(smp_processors_ready) {
  282. register int high = smp_highest_cpu;
  283. unsigned long flags;
  284. spin_lock_irqsave(&cross_call_lock, flags);
  285. {
  286. /* If you make changes here, make sure gcc generates proper code... */
  287. smpfunc_t f asm("i0") = func;
  288. unsigned long a1 asm("i1") = arg1;
  289. unsigned long a2 asm("i2") = arg2;
  290. unsigned long a3 asm("i3") = arg3;
  291. unsigned long a4 asm("i4") = arg4;
  292. unsigned long a5 asm("i5") = arg5;
  293. __asm__ __volatile__("
  294. std %0, [%6]
  295. std %2, [%6 + 8]
  296. std %4, [%6 + 16]" : : 
  297. "r"(f), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
  298. "r" (&ccall_info.func));
  299. }
  300. /* Init receive/complete mapping, plus fire the IPI's off. */
  301. {
  302. register unsigned long mask;
  303. register int i;
  304. mask = (cpu_present_map & ~(1 << hard_smp4d_processor_id()));
  305. for(i = 0; i <= high; i++) {
  306. if(mask & (1 << i)) {
  307. ccall_info.processors_in[i] = 0;
  308. ccall_info.processors_out[i] = 0;
  309. sun4d_send_ipi(i, IRQ_CROSS_CALL);
  310. }
  311. }
  312. }
  313. {
  314. register int i;
  315. i = 0;
  316. do {
  317. while(!ccall_info.processors_in[i])
  318. barrier();
  319. } while(++i <= high);
  320. i = 0;
  321. do {
  322. while(!ccall_info.processors_out[i])
  323. barrier();
  324. } while(++i <= high);
  325. }
  326. spin_unlock_irqrestore(&cross_call_lock, flags);
  327. }
  328. }
  329. /* Running cross calls. */
  330. void smp4d_cross_call_irq(void)
  331. {
  332. int i = hard_smp4d_processor_id();
  333. ccall_info.processors_in[i] = 1;
  334. ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
  335. ccall_info.arg4, ccall_info.arg5);
  336. ccall_info.processors_out[i] = 1;
  337. }
  338. static int smp4d_stop_cpu_sender;
  339. static void smp4d_stop_cpu(void)
  340. {
  341. int me = hard_smp4d_processor_id();
  342. if (me != smp4d_stop_cpu_sender)
  343. while(1) barrier();
  344. }
  345. /* Cross calls, in order to work efficiently and atomically do all
  346.  * the message passing work themselves, only stopcpu and reschedule
  347.  * messages come through here.
  348.  */
  349. void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
  350. {
  351. int me = hard_smp4d_processor_id();
  352. SMP_PRINTK(("smp4d_message_pass %d %d %08lx %dn", target, msg, data, wait));
  353. if (msg == MSG_STOP_CPU && target == MSG_ALL_BUT_SELF) {
  354. unsigned long flags;
  355. static spinlock_t stop_cpu_lock = SPIN_LOCK_UNLOCKED;
  356. spin_lock_irqsave(&stop_cpu_lock, flags);
  357. smp4d_stop_cpu_sender = me;
  358. smp4d_cross_call((smpfunc_t)smp4d_stop_cpu, 0, 0, 0, 0, 0);
  359. spin_unlock_irqrestore(&stop_cpu_lock, flags);
  360. }
  361. printk("Yeeee, trying to send SMP msg(%d) to %d on cpu %dn", msg, target, me);
  362. panic("Bogon SMP message pass.");
  363. }
  364. extern unsigned int prof_multiplier[NR_CPUS];
  365. extern unsigned int prof_counter[NR_CPUS];
  366. extern void sparc_do_profile(unsigned long pc, unsigned long o7);
  367. void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
  368. {
  369. int cpu = hard_smp4d_processor_id();
  370. static int cpu_tick[NR_CPUS];
  371. static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
  372. bw_get_prof_limit(cpu);
  373. bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */
  374. cpu_tick[cpu]++;
  375. if (!(cpu_tick[cpu] & 15)) {
  376. if (cpu_tick[cpu] == 0x60)
  377. cpu_tick[cpu] = 0;
  378. cpu_leds[cpu] = led_mask[cpu_tick[cpu] >> 4];
  379. show_leds(cpu);
  380. }
  381. if(!user_mode(regs))
  382. sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
  383. if(!--prof_counter[cpu]) {
  384. int user = user_mode(regs);
  385. irq_enter(cpu, 0);
  386. update_process_times(user);
  387. irq_exit(cpu, 0);
  388. prof_counter[cpu] = prof_multiplier[cpu];
  389. }
  390. }
  391. extern unsigned int lvl14_resolution;
  392. static void __init smp_setup_percpu_timer(void)
  393. {
  394. int cpu = hard_smp4d_processor_id();
  395. prof_counter[cpu] = prof_multiplier[cpu] = 1;
  396. load_profile_irq(cpu, lvl14_resolution);
  397. }
  398. void __init smp4d_blackbox_id(unsigned *addr)
  399. {
  400. int rd = *addr & 0x3e000000;
  401. addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */
  402. addr[1] = 0x01000000;     /* nop */
  403. addr[2] = 0x01000000;     /* nop */
  404. }
  405. void __init smp4d_blackbox_current(unsigned *addr)
  406. {
  407. /* We have a nice Linux current register :) */
  408. int rd = addr[1] & 0x3e000000;
  409. addr[0] = 0x10800006; /* b .+24 */
  410. addr[1] = 0xc0800820 | rd; /* lda [%g0] ASI_M_VIKING_TMP2, reg */
  411. }
  412. void __init sun4d_init_smp(void)
  413. {
  414. int i;
  415. extern unsigned int patchme_store_new_current[];
  416. extern unsigned int t_nmi[], linux_trap_ipi15_sun4d[], linux_trap_ipi15_sun4m[];
  417. /* Store current into Linux current register :) */
  418. __asm__ __volatile__("sta %%g6, [%%g0] %0" : : "i"(ASI_M_VIKING_TMP2));
  419. /* Patch switch_to */
  420. patchme_store_new_current[0] = (patchme_store_new_current[0] & 0x3e000000) | 0xc0a00820;
  421. /* Patch ipi15 trap table */
  422. t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m);
  423. /* And set btfixup... */
  424. BTFIXUPSET_BLACKBOX(smp_processor_id, smp4d_blackbox_id);
  425. BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
  426. BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
  427. BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM);
  428. BTFIXUPSET_CALL(__smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
  429. for (i = 0; i < NR_CPUS; i++) {
  430. ccall_info.processors_in[i] = 1;
  431. ccall_info.processors_out[i] = 1;
  432. }
  433. }