fix to allow usb modules to compile
[linux-2.4.21-pre4.git] / arch / ppc / kernel / idle.c
1 /*
2  * BK Id: SCCS/s.idle.c 1.45 01/16/03 11:02:49 dgibson
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  *  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.
19  */
20 #include <linux/config.h>
21 #include <linux/errno.h>
22 #include <linux/sched.h>
23 #include <linux/kernel.h>
24 #include <linux/mm.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>
32
33 #include <asm/pgtable.h>
34 #include <asm/uaccess.h>
35 #include <asm/system.h>
36 #include <asm/io.h>
37 #include <asm/processor.h>
38 #include <asm/mmu.h>
39 #include <asm/cache.h>
40 #include <asm/cputable.h>
41 #ifdef CONFIG_PPC_ISERIES
42 #include <asm/time.h>
43 #include <asm/iSeries/LparData.h>
44 #include <asm/iSeries/HvCall.h>
45 #include <asm/hardirq.h>
46
47 static void yield_shared_processor(void);
48 static void run_light_on(int on);
49
50 extern unsigned long yield_count;
51
52 #else /* CONFIG_PPC_ISERIES */
53 #define run_light_on(x)         do { } while (0)
54 #endif /* CONFIG_PPC_ISERIES */
55
56 void zero_paged(void);
57 #ifdef CONFIG_6xx
58 void power_save_6xx(void);
59 #endif
60 #ifdef CONFIG_4xx
61 void power_save_4xx(void);
62 #endif
63
64 #ifdef CONFIG_6xx
65 int powersave_lowspeed = 0;
66 int powersave_nap = 0;
67 #endif
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 */
73
74 int idled(void)
75 {
76         int do_power_save = 0;
77
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))
81                 do_power_save = 1;
82
83         //REX:
84         //printk("Powersave is %d\n", do_power_save);
85         /* endless loop with no priority at all */
86         current->nice = 20;
87         current->counter = -100;
88         init_idle();
89         for (;;) {
90 #ifdef CONFIG_PPC_ISERIES
91                 if (!current->need_resched) {
92                         /* Turn off the run light */
93                         run_light_on(0);
94                         yield_shared_processor(); 
95                 }
96                 HMT_low();
97 #endif
98 #ifdef CONFIG_SMP
99                 if (!do_power_save) {
100                         /*
101                          * Deal with another CPU just having chosen a thread to
102                          * run here:
103                          */
104                         int oldval = xchg(&current->need_resched, -1);
105
106                         if (!oldval) {
107                                 while(current->need_resched == -1)
108                                         ; /* Do Nothing */
109                         }
110                 }
111 #endif
112 //REX:
113 #if 1           
114 #ifdef CONFIG_6xx
115                 if (do_power_save && !current->need_resched)
116                 {       
117                         power_save_6xx();
118                         //REX:
119                         //printk("Return from power_save_6xx\n");
120                 }
121 #endif /* CONFIG_6xx */
122 #endif          
123 #ifdef CONFIG_4xx
124                 if (do_power_save && !current->need_resched)
125                         power_save_4xx();
126 #endif /* CONFIG_4xx */
127
128                 if (current->need_resched) {
129                         run_light_on(1);
130                         schedule();
131                         check_pgt_cache();
132                 }
133 #ifdef CONFIG_PPC_ISERIES
134                 else {
135                         run_light_on(0);
136                         yield_shared_processor();
137                         HMT_low();
138                 }
139 #endif /* CONFIG_PPC_ISERIES */
140         }
141         return 0;
142 }
143
144 /*
145  * SMP entry into the idle task - calls the same thing as the
146  * non-smp versions. -- Cort
147  */
148 int cpu_idle(void)
149 {
150         idled();
151         return 0; 
152 }
153
154 #if 0
155 /*
156  * Returns a pre-zero'd page from the list otherwise returns
157  * NULL.
158  */
159 unsigned long get_zero_page_fast(void)
160 {
161         unsigned long page = 0;
162
163         atomic_inc(&zero_cache_calls);
164         if ( zero_quicklist )
165         {
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 */
170                         PPC405_ERR77(0,%3)
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)
175                         : "cc" );
176 #ifdef CONFIG_SMP
177                 /* if another cpu beat us above this can happen -- Cort */
178                 if ( page == 0 ) 
179                         return 0;
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
184                  * less page -- Cort
185                  */
186                 atomic_inc((atomic_t *)&zero_cache_hits);
187                 atomic_dec((atomic_t *)&zero_cache_sz);
188                 
189                 /* zero out the pointer to next in the page */
190                 *(unsigned long *)page = 0;
191                 return page;
192         }
193         return 0;
194 }
195
196 /*
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.
202  */
203 int zero_cache_water[2] = { 25, 96 }; /* high and low water marks for zero cache */
204 void zero_paged(void)
205 {
206         unsigned long pageptr = 0;      /* current page being zero'd */
207         unsigned long bytecount = 0;  
208         register unsigned long tmp;
209         pte_t *pte;
210
211         if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
212                 return;
213         while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
214         {
215                 /*
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.
219                  */
220                 pageptr = __get_free_pages(GFP_ATOMIC, 0);
221                 if ( !pageptr )
222                         return;
223                 
224                 if ( current->need_resched )
225                         schedule();
226                 
227                 /*
228                  * Make the page no cache so we don't blow our cache with 0's
229                  */
230                 pte = find_pte(&init_mm, pageptr);
231                 if ( !pte )
232                 {
233                         printk("pte NULL in zero_paged()\n");
234                         return;
235                 }
236                 
237                 pte_uncache(*pte);
238                 flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
239                 /*
240                  * Important here to not take time away from real processes.
241                  */
242                 for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
243                 {
244                         if ( current->need_resched )
245                                 schedule();
246                         *(unsigned long *)(bytecount + pageptr) = 0;
247                 }
248                 
249                 /*
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.
258                  * -- Cort
259                  */
260                 
261                 /* turn cache on for this page */
262                 pte_cache(*pte);
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 */
267 #ifdef CONFIG_SMP
268                         "    sync\n"            /* let store settle */
269 #endif                  
270                         PPC405_ERR77(0,%2)
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)
275                         : "cc" );
276                 /*
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
283                  * reads it.  -- Cort
284                  */
285                 atomic_inc((atomic_t *)&zero_cache_sz);
286                 atomic_inc((atomic_t *)&zero_cache_total);
287         }
288 }
289 #endif /* 0 */
290
291 #ifdef CONFIG_PPC_ISERIES
292
293 extern void fake_interrupt(void);
294 extern u64  get_tb64(void);
295
296 void run_light_on(int on)
297 {
298         unsigned long CTRL;
299
300         CTRL = mfspr(CTRLF);
301         CTRL = on? (CTRL | RUNLATCH): (CTRL & ~RUNLATCH);
302         mtspr(CTRLT, CTRL);
303 }
304
305 void yield_shared_processor(void)
306 {
307         struct Paca *paca;
308         u64 tb;
309
310         /* Poll for I/O events */
311         __cli();
312         __sti();
313         
314         paca = (struct Paca *)mfspr(SPRG1);
315         if ( paca->xLpPaca.xSharedProc ) {
316                 HvCall_setEnabledInterrupts( HvCall_MaskIPI |
317                         HvCall_MaskLpEvent |
318                         HvCall_MaskLpProd |
319                         HvCall_MaskTimeout );
320
321                 /*
322                  * Check here for any of the above pending...
323                  * IPI and Decrementers are indicated in ItLpPaca
324                  * LpEvents are indicated on the LpQueue
325                  *
326                  * Disabling/enabling will check for LpEvents, IPIs
327                  * and decrementers
328                  */
329                 __cli();
330                 __sti();
331
332                 ++yield_count;
333
334                 /* Get current tb value */
335                 tb = get_tb64();
336                 /* Compute future tb value when yield will expire */
337                 tb += tb_ticks_per_jiffy;
338                 HvCall_yieldProcessor( HvCall_YieldTimed, tb );
339
340                 /* Check here for any of the above pending or timeout expired*/
341                 __cli();
342                 /*
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
346                  */
347                 paca->xLpPaca.xDecrInt = 1;
348                 __sti();
349         }
350 }
351 #endif /* CONFIG_PPC_ISERIES */