2 * BK Id: SCCS/s.idle.c 1.45 01/16/03 11:02:49 dgibson
5 * Idle daemon for PowerPC. Idle daemon will handle any action
6 * that needs to be taken when the system becomes idle.
8 * Written by Cort Dougan (cort@cs.nmt.edu)
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.
15 * 07/27/02 - Armin & Tom.
16 * added powersave idle loop indirection scheme borrowed from
17 * i386 & arm so other PPC archs can have their own if the
18 * default is not sufficiant.
20 #include <linux/config.h>
21 #include <linux/errno.h>
22 #include <linux/sched.h>
23 #include <linux/kernel.h>
25 #include <linux/smp.h>
26 #include <linux/smp_lock.h>
27 #include <linux/stddef.h>
28 #include <linux/unistd.h>
29 #include <linux/ptrace.h>
30 #include <linux/slab.h>
31 #include <linux/stringify.h>
33 #include <asm/pgtable.h>
34 #include <asm/uaccess.h>
35 #include <asm/system.h>
37 #include <asm/processor.h>
39 #include <asm/cache.h>
40 #include <asm/cputable.h>
41 #ifdef CONFIG_PPC_ISERIES
43 #include <asm/iSeries/LparData.h>
44 #include <asm/iSeries/HvCall.h>
45 #include <asm/hardirq.h>
47 static void yield_shared_processor(void);
48 static void run_light_on(int on);
50 extern unsigned long yield_count;
52 #else /* CONFIG_PPC_ISERIES */
53 #define run_light_on(x) do { } while (0)
54 #endif /* CONFIG_PPC_ISERIES */
56 void zero_paged(void);
58 void power_save_6xx(void);
61 void power_save_4xx(void);
65 int powersave_lowspeed = 0;
66 int powersave_nap = 0;
68 unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
69 atomic_t zerototal; /* # pages zero'd over time */
70 atomic_t zeropage_hits; /* # zero'd pages request that we've done */
71 atomic_t zero_sz; /* # currently pre-zero'd pages */
72 atomic_t zeropage_calls; /* # zero'd pages request that've been made */
76 int do_power_save = 0;
78 /* Check if CPU can powersave (get rid of that soon!) */
79 if (cur_cpu_spec[smp_processor_id()]->cpu_features &
80 (CPU_FTR_CAN_DOZE | CPU_FTR_CAN_NAP))
84 //printk("Powersave is %d\n", do_power_save);
85 /* endless loop with no priority at all */
87 current->counter = -100;
90 #ifdef CONFIG_PPC_ISERIES
91 if (!current->need_resched) {
92 /* Turn off the run light */
94 yield_shared_processor();
101 * Deal with another CPU just having chosen a thread to
104 int oldval = xchg(¤t->need_resched, -1);
107 while(current->need_resched == -1)
115 if (do_power_save && !current->need_resched)
119 //printk("Return from power_save_6xx\n");
121 #endif /* CONFIG_6xx */
124 if (do_power_save && !current->need_resched)
126 #endif /* CONFIG_4xx */
128 if (current->need_resched) {
133 #ifdef CONFIG_PPC_ISERIES
136 yield_shared_processor();
139 #endif /* CONFIG_PPC_ISERIES */
145 * SMP entry into the idle task - calls the same thing as the
146 * non-smp versions. -- Cort
156 * Returns a pre-zero'd page from the list otherwise returns
159 unsigned long get_zero_page_fast(void)
161 unsigned long page = 0;
163 atomic_inc(&zero_cache_calls);
164 if ( zero_quicklist )
166 /* atomically remove this page from the list */
167 register unsigned long tmp;
168 asm ( "101:lwarx %1,0,%3\n" /* reserve zero_cache */
169 " lwz %0,0(%1)\n" /* get next -- new zero_cache */
171 " stwcx. %0,0,%3\n" /* update zero_cache */
172 " bne- 101b\n" /* if lost reservation try again */
173 : "=&r" (tmp), "=&r" (page), "+m" (zero_cache)
174 : "r" (&zero_quicklist)
177 /* if another cpu beat us above this can happen -- Cort */
180 #endif /* CONFIG_SMP */
181 /* we can update zerocount after the fact since it is not
182 * used for anything but control of a loop which doesn't
183 * matter since it won't affect anything if it zeros one
186 atomic_inc((atomic_t *)&zero_cache_hits);
187 atomic_dec((atomic_t *)&zero_cache_sz);
189 /* zero out the pointer to next in the page */
190 *(unsigned long *)page = 0;
197 * Experimental stuff to zero out pages in the idle task
198 * to speed up get_free_pages(). Zero's out pages until
199 * we've reached the limit of zero'd pages. We handle
200 * reschedule()'s in here so when we return we know we've
201 * zero'd all we need to for now.
203 int zero_cache_water[2] = { 25, 96 }; /* high and low water marks for zero cache */
204 void zero_paged(void)
206 unsigned long pageptr = 0; /* current page being zero'd */
207 unsigned long bytecount = 0;
208 register unsigned long tmp;
211 if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
213 while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
216 * Mark a page as reserved so we can mess with it
217 * If we're interrupted we keep this page and our place in it
218 * since we validly hold it and it's reserved for us.
220 pageptr = __get_free_pages(GFP_ATOMIC, 0);
224 if ( current->need_resched )
228 * Make the page no cache so we don't blow our cache with 0's
230 pte = find_pte(&init_mm, pageptr);
233 printk("pte NULL in zero_paged()\n");
238 flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
240 * Important here to not take time away from real processes.
242 for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
244 if ( current->need_resched )
246 *(unsigned long *)(bytecount + pageptr) = 0;
250 * If we finished zero-ing out a page add this page to
251 * the zero_cache atomically -- we can't use
252 * down/up since we can't sleep in idle.
253 * Disabling interrupts is also a bad idea since we would
254 * steal time away from real processes.
255 * We can also have several zero_paged's running
256 * on different processors so we can't interfere with them.
257 * So we update the list atomically without locking it.
261 /* turn cache on for this page */
263 flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
264 /* atomically add this page to the list */
265 asm ( "101:lwarx %0,0,%2\n" /* reserve zero_cache */
266 " stw %0,0(%3)\n" /* update *pageptr */
268 " sync\n" /* let store settle */
271 " stwcx. %3,0,%2\n" /* update zero_cache in mem */
272 " bne- 101b\n" /* if lost reservation try again */
273 : "=&r" (tmp), "+m" (zero_quicklist)
274 : "r" (&zero_quicklist), "r" (pageptr)
277 * This variable is used in the above loop and nowhere
278 * else so the worst that could happen is we would
279 * zero out one more or one less page than we want
280 * per processor on the machine. This is because
281 * we could add our page to the list but not have
282 * zerocount updated yet when another processor
285 atomic_inc((atomic_t *)&zero_cache_sz);
286 atomic_inc((atomic_t *)&zero_cache_total);
291 #ifdef CONFIG_PPC_ISERIES
293 extern void fake_interrupt(void);
294 extern u64 get_tb64(void);
296 void run_light_on(int on)
301 CTRL = on? (CTRL | RUNLATCH): (CTRL & ~RUNLATCH);
305 void yield_shared_processor(void)
310 /* Poll for I/O events */
314 paca = (struct Paca *)mfspr(SPRG1);
315 if ( paca->xLpPaca.xSharedProc ) {
316 HvCall_setEnabledInterrupts( HvCall_MaskIPI |
319 HvCall_MaskTimeout );
322 * Check here for any of the above pending...
323 * IPI and Decrementers are indicated in ItLpPaca
324 * LpEvents are indicated on the LpQueue
326 * Disabling/enabling will check for LpEvents, IPIs
334 /* Get current tb value */
336 /* Compute future tb value when yield will expire */
337 tb += tb_ticks_per_jiffy;
338 HvCall_yieldProcessor( HvCall_YieldTimed, tb );
340 /* Check here for any of the above pending or timeout expired*/
343 * The decrementer stops during the yield. Just force
344 * a fake decrementer now and the timer_interrupt
345 * code will straighten it all out
347 paca->xLpPaca.xDecrInt = 1;
351 #endif /* CONFIG_PPC_ISERIES */