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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.idle.c 1.18 12/01/01 20:09:06 benh
  3.  */
  4. /*
  5.  * Idle daemon for PowerPC.  Idle daemon will handle any action
  6.  * that needs to be taken when the system becomes idle.
  7.  *
  8.  * Written by Cort Dougan (cort@cs.nmt.edu)
  9.  *
  10.  * This program is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU General Public License
  12.  * as published by the Free Software Foundation; either version
  13.  * 2 of the License, or (at your option) any later version.
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/errno.h>
  17. #include <linux/sched.h>
  18. #include <linux/kernel.h>
  19. #include <linux/mm.h>
  20. #include <linux/smp.h>
  21. #include <linux/smp_lock.h>
  22. #include <linux/stddef.h>
  23. #include <linux/unistd.h>
  24. #include <linux/ptrace.h>
  25. #include <linux/slab.h>
  26. #include <asm/pgtable.h>
  27. #include <asm/uaccess.h>
  28. #include <asm/system.h>
  29. #include <asm/io.h>
  30. #include <asm/processor.h>
  31. #include <asm/mmu.h>
  32. #include <asm/cache.h>
  33. #include <asm/cputable.h>
  34. void zero_paged(void);
  35. void power_save(void);
  36. unsigned long zero_paged_on = 0;
  37. unsigned long powersave_nap = 0;
  38. unsigned long *zero_cache;    /* head linked list of pre-zero'd pages */
  39. atomic_t zerototal;      /* # pages zero'd over time */
  40. atomic_t zeropage_hits;  /* # zero'd pages request that we've done */
  41. atomic_t zero_sz;       /* # currently pre-zero'd pages */
  42. atomic_t zeropage_calls; /* # zero'd pages request that've been made */
  43. int idled(void)
  44. {
  45. int do_power_save = 0;
  46. if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)
  47. do_power_save = 1;
  48. /* endless loop with no priority at all */
  49. current->nice = 20;
  50. current->counter = -100;
  51. init_idle();
  52. for (;;) {
  53. #ifdef CONFIG_SMP
  54. if (!do_power_save) {
  55. /*
  56.  * Deal with another CPU just having chosen a thread to
  57.  * run here:
  58.  */
  59. int oldval = xchg(&current->need_resched, -1);
  60. if (!oldval) {
  61. while(current->need_resched == -1)
  62. ; /* Do Nothing */
  63. }
  64. }
  65. #endif
  66. if (do_power_save && !current->need_resched)
  67. power_save();
  68. if (current->need_resched) {
  69. schedule();
  70. check_pgt_cache();
  71. }
  72. }
  73. return 0;
  74. }
  75. /*
  76.  * SMP entry into the idle task - calls the same thing as the
  77.  * non-smp versions. -- Cort
  78.  */
  79. int cpu_idle(void)
  80. {
  81. idled();
  82. return 0; 
  83. }
  84. #if 0
  85. /*
  86.  * Returns a pre-zero'd page from the list otherwise returns
  87.  * NULL.
  88.  */
  89. unsigned long get_zero_page_fast(void)
  90. {
  91. unsigned long page = 0;
  92. atomic_inc(&zero_cache_calls);
  93. if ( zero_quicklist )
  94. {
  95. /* atomically remove this page from the list */
  96. register unsigned long tmp;
  97. asm ( "101:lwarx  %1,0,%3n"  /* reserve zero_cache */
  98. "    lwz    %0,0(%1)n" /* get next -- new zero_cache */
  99. "    stwcx. %0,0,%3n"  /* update zero_cache */
  100. "    bne-   101bn"     /* if lost reservation try again */
  101. : "=&r" (tmp), "=&r" (page), "+m" (zero_cache)
  102. : "r" (&zero_quicklist)
  103. : "cc" );
  104. #ifdef CONFIG_SMP
  105. /* if another cpu beat us above this can happen -- Cort */
  106. if ( page == 0 ) 
  107. return 0;
  108. #endif /* CONFIG_SMP */
  109. /* we can update zerocount after the fact since it is not
  110.  * used for anything but control of a loop which doesn't
  111.  * matter since it won't affect anything if it zeros one
  112.  * less page -- Cort
  113.  */
  114. atomic_inc((atomic_t *)&zero_cache_hits);
  115. atomic_dec((atomic_t *)&zero_cache_sz);
  116. /* zero out the pointer to next in the page */
  117. *(unsigned long *)page = 0;
  118. return page;
  119. }
  120. return 0;
  121. }
  122. /*
  123.  * Experimental stuff to zero out pages in the idle task
  124.  * to speed up get_free_pages(). Zero's out pages until
  125.  * we've reached the limit of zero'd pages.  We handle
  126.  * reschedule()'s in here so when we return we know we've
  127.  * zero'd all we need to for now.
  128.  */
  129. int zero_cache_water[2] = { 25, 96 }; /* high and low water marks for zero cache */
  130. void zero_paged(void)
  131. {
  132. unsigned long pageptr = 0; /* current page being zero'd */
  133. unsigned long bytecount = 0;  
  134.         register unsigned long tmp;
  135. pte_t *pte;
  136. if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
  137. return;
  138. while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
  139. {
  140. /*
  141.  * Mark a page as reserved so we can mess with it
  142.  * If we're interrupted we keep this page and our place in it
  143.  * since we validly hold it and it's reserved for us.
  144.  */
  145. pageptr = __get_free_pages(GFP_ATOMIC, 0);
  146. if ( !pageptr )
  147. return;
  148. if ( current->need_resched )
  149. schedule();
  150. /*
  151.  * Make the page no cache so we don't blow our cache with 0's
  152.  */
  153. pte = find_pte(&init_mm, pageptr);
  154. if ( !pte )
  155. {
  156. printk("pte NULL in zero_paged()n");
  157. return;
  158. }
  159. pte_uncache(*pte);
  160. flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
  161. /*
  162.  * Important here to not take time away from real processes.
  163.  */
  164. for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
  165. {
  166. if ( current->need_resched )
  167. schedule();
  168. *(unsigned long *)(bytecount + pageptr) = 0;
  169. }
  170. /*
  171.  * If we finished zero-ing out a page add this page to
  172.  * the zero_cache atomically -- we can't use
  173.  * down/up since we can't sleep in idle.
  174.  * Disabling interrupts is also a bad idea since we would
  175.  * steal time away from real processes.
  176.  * We can also have several zero_paged's running
  177.  * on different processors so we can't interfere with them.
  178.  * So we update the list atomically without locking it.
  179.  * -- Cort
  180.  */
  181. /* turn cache on for this page */
  182. pte_cache(*pte);
  183. flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
  184. /* atomically add this page to the list */
  185. asm ( "101:lwarx  %0,0,%2n"  /* reserve zero_cache */
  186. "    stw    %0,0(%3)n" /* update *pageptr */
  187. #ifdef CONFIG_SMP
  188. "    syncn"            /* let store settle */
  189. #endif
  190. "    stwcx. %3,0,%2n"  /* update zero_cache in mem */
  191. "    bne-   101bn"     /* if lost reservation try again */
  192. : "=&r" (tmp), "+m" (zero_quicklist)
  193. : "r" (&zero_quicklist), "r" (pageptr)
  194. : "cc" );
  195. /*
  196.  * This variable is used in the above loop and nowhere
  197.  * else so the worst that could happen is we would
  198.  * zero out one more or one less page than we want
  199.  * per processor on the machine.  This is because
  200.  * we could add our page to the list but not have
  201.  * zerocount updated yet when another processor
  202.  * reads it.  -- Cort
  203.  */
  204. atomic_inc((atomic_t *)&zero_cache_sz);
  205. atomic_inc((atomic_t *)&zero_cache_total);
  206. }
  207. }
  208. #endif /* 0 */
  209. void power_save(void)
  210. {
  211. unsigned long hid0;
  212. int nap = powersave_nap;
  213. /* 7450 has no DOZE mode mode, we return if powersave_nap
  214.  * isn't enabled
  215.  */
  216. if (!nap &&  cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_SPEC7450)
  217. return;
  218. /*
  219.  * Disable interrupts to prevent a lost wakeup
  220.  * when going to sleep.  This is necessary even with
  221.  * RTLinux since we are not guaranteed an interrupt
  222.  * didn't come in and is waiting for a __sti() before
  223.  * emulating one.  This way, we really do hard disable.
  224.  * 
  225.  * We assume that we're sti-ed when we come in here.  We
  226.  * are in the idle loop so if we're cli-ed then it's a bug
  227.  * anyway.
  228.  *  -- Cort
  229.  */
  230. _nmask_and_or_msr(MSR_EE, 0);
  231. if (!current->need_resched)
  232. {
  233. asm("mfspr %0,1008" : "=r" (hid0) :);
  234. hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
  235. hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
  236. asm("mtspr 1008,%0" : : "r" (hid0));
  237. /* set the POW bit in the MSR, and enable interrupts
  238.  * so we wake up sometime! */
  239. _nmask_and_or_msr(0, MSR_POW | MSR_EE);
  240. }
  241. _nmask_and_or_msr(0, MSR_EE);
  242. }