Merge branch 'srp' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[linux-2.6] / arch / powerpc / kernel / misc_64.S
1 /*
2  *  arch/powerpc/kernel/misc64.S
3  *
4  * This file contains miscellaneous low-level functions.
5  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6  *
7  * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
8  * and Paul Mackerras.
9  * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
10  * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) 
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version
15  * 2 of the License, or (at your option) any later version.
16  *
17  */
18
19 #include <linux/config.h>
20 #include <linux/sys.h>
21 #include <asm/unistd.h>
22 #include <asm/errno.h>
23 #include <asm/processor.h>
24 #include <asm/page.h>
25 #include <asm/cache.h>
26 #include <asm/ppc_asm.h>
27 #include <asm/asm-offsets.h>
28 #include <asm/cputable.h>
29 #include <asm/thread_info.h>
30
31         .text
32
33 /*
34  * Returns (address we are running at) - (address we were linked at)
35  * for use before the text and data are mapped to KERNELBASE.
36  */
37
38 _GLOBAL(reloc_offset)
39         mflr    r0
40         bl      1f
41 1:      mflr    r3
42         LOADADDR(r4,1b)
43         subf    r3,r4,r3
44         mtlr    r0
45         blr
46
47 /*
48  * add_reloc_offset(x) returns x + reloc_offset().
49  */
50 _GLOBAL(add_reloc_offset)
51         mflr    r0
52         bl      1f
53 1:      mflr    r5
54         LOADADDR(r4,1b)
55         subf    r5,r4,r5
56         add     r3,r3,r5
57         mtlr    r0
58         blr
59
60 _GLOBAL(get_msr)
61         mfmsr   r3
62         blr
63
64 _GLOBAL(get_dar)
65         mfdar   r3
66         blr
67
68 _GLOBAL(get_srr0)
69         mfsrr0  r3
70         blr
71
72 _GLOBAL(get_srr1)
73         mfsrr1  r3
74         blr
75         
76 _GLOBAL(get_sp)
77         mr      r3,r1
78         blr
79
80 #ifdef CONFIG_IRQSTACKS
81 _GLOBAL(call_do_softirq)
82         mflr    r0
83         std     r0,16(r1)
84         stdu    r1,THREAD_SIZE-112(r3)
85         mr      r1,r3
86         bl      .__do_softirq
87         ld      r1,0(r1)
88         ld      r0,16(r1)
89         mtlr    r0
90         blr
91
92 _GLOBAL(call_handle_IRQ_event)
93         mflr    r0
94         std     r0,16(r1)
95         stdu    r1,THREAD_SIZE-112(r6)
96         mr      r1,r6
97         bl      .handle_IRQ_event
98         ld      r1,0(r1)
99         ld      r0,16(r1)
100         mtlr    r0
101         blr
102 #endif /* CONFIG_IRQSTACKS */
103
104         /*
105  * To be called by C code which needs to do some operations with MMU
106  * disabled. Note that interrupts have to be disabled by the caller
107  * prior to calling us. The code called _MUST_ be in the RMO of course
108  * and part of the linear mapping as we don't attempt to translate the
109  * stack pointer at all. The function is called with the stack switched
110  * to this CPU emergency stack
111  *
112  * prototype is void *call_with_mmu_off(void *func, void *data);
113  *
114  * the called function is expected to be of the form
115  *
116  * void *called(void *data); 
117  */
118 _GLOBAL(call_with_mmu_off)
119         mflr    r0                      /* get link, save it on stackframe */
120         std     r0,16(r1)
121         mr      r1,r5                   /* save old stack ptr */
122         ld      r1,PACAEMERGSP(r13)     /* get emerg. stack */
123         subi    r1,r1,STACK_FRAME_OVERHEAD
124         std     r0,16(r1)               /* save link on emerg. stack */
125         std     r5,0(r1)                /* save old stack ptr in backchain */
126         ld      r3,0(r3)                /* get to real function ptr (assume same TOC) */
127         bl      2f                      /* we need LR to return, continue at label 2 */
128
129         ld      r0,16(r1)               /* we return here from the call, get LR and */
130         ld      r1,0(r1)                /* .. old stack ptr */
131         mtspr   SPRN_SRR0,r0            /* and get back to virtual mode with these */
132         mfmsr   r4
133         ori     r4,r4,MSR_IR|MSR_DR
134         mtspr   SPRN_SRR1,r4
135         rfid
136
137 2:      mtspr   SPRN_SRR0,r3            /* coming from above, enter real mode */
138         mr      r3,r4                   /* get parameter */
139         mfmsr   r0
140         ori     r0,r0,MSR_IR|MSR_DR
141         xori    r0,r0,MSR_IR|MSR_DR
142         mtspr   SPRN_SRR1,r0
143         rfid
144
145
146         .section        ".toc","aw"
147 PPC64_CACHES:
148         .tc             ppc64_caches[TC],ppc64_caches
149         .section        ".text"
150
151 /*
152  * Write any modified data cache blocks out to memory
153  * and invalidate the corresponding instruction cache blocks.
154  *
155  * flush_icache_range(unsigned long start, unsigned long stop)
156  *
157  *   flush all bytes from start through stop-1 inclusive
158  */
159
160 _KPROBE(__flush_icache_range)
161
162 /*
163  * Flush the data cache to memory 
164  * 
165  * Different systems have different cache line sizes
166  * and in some cases i-cache and d-cache line sizes differ from
167  * each other.
168  */
169         ld      r10,PPC64_CACHES@toc(r2)
170         lwz     r7,DCACHEL1LINESIZE(r10)/* Get cache line size */
171         addi    r5,r7,-1
172         andc    r6,r3,r5                /* round low to line bdy */
173         subf    r8,r6,r4                /* compute length */
174         add     r8,r8,r5                /* ensure we get enough */
175         lwz     r9,DCACHEL1LOGLINESIZE(r10)     /* Get log-2 of cache line size */
176         srw.    r8,r8,r9                /* compute line count */
177         beqlr                           /* nothing to do? */
178         mtctr   r8
179 1:      dcbst   0,r6
180         add     r6,r6,r7
181         bdnz    1b
182         sync
183
184 /* Now invalidate the instruction cache */
185         
186         lwz     r7,ICACHEL1LINESIZE(r10)        /* Get Icache line size */
187         addi    r5,r7,-1
188         andc    r6,r3,r5                /* round low to line bdy */
189         subf    r8,r6,r4                /* compute length */
190         add     r8,r8,r5
191         lwz     r9,ICACHEL1LOGLINESIZE(r10)     /* Get log-2 of Icache line size */
192         srw.    r8,r8,r9                /* compute line count */
193         beqlr                           /* nothing to do? */
194         mtctr   r8
195 2:      icbi    0,r6
196         add     r6,r6,r7
197         bdnz    2b
198         isync
199         blr
200         .previous .text
201 /*
202  * Like above, but only do the D-cache.
203  *
204  * flush_dcache_range(unsigned long start, unsigned long stop)
205  *
206  *    flush all bytes from start to stop-1 inclusive
207  */
208 _GLOBAL(flush_dcache_range)
209
210 /*
211  * Flush the data cache to memory 
212  * 
213  * Different systems have different cache line sizes
214  */
215         ld      r10,PPC64_CACHES@toc(r2)
216         lwz     r7,DCACHEL1LINESIZE(r10)        /* Get dcache line size */
217         addi    r5,r7,-1
218         andc    r6,r3,r5                /* round low to line bdy */
219         subf    r8,r6,r4                /* compute length */
220         add     r8,r8,r5                /* ensure we get enough */
221         lwz     r9,DCACHEL1LOGLINESIZE(r10)     /* Get log-2 of dcache line size */
222         srw.    r8,r8,r9                /* compute line count */
223         beqlr                           /* nothing to do? */
224         mtctr   r8
225 0:      dcbst   0,r6
226         add     r6,r6,r7
227         bdnz    0b
228         sync
229         blr
230
231 /*
232  * Like above, but works on non-mapped physical addresses.
233  * Use only for non-LPAR setups ! It also assumes real mode
234  * is cacheable. Used for flushing out the DART before using
235  * it as uncacheable memory 
236  *
237  * flush_dcache_phys_range(unsigned long start, unsigned long stop)
238  *
239  *    flush all bytes from start to stop-1 inclusive
240  */
241 _GLOBAL(flush_dcache_phys_range)
242         ld      r10,PPC64_CACHES@toc(r2)
243         lwz     r7,DCACHEL1LINESIZE(r10)        /* Get dcache line size */
244         addi    r5,r7,-1
245         andc    r6,r3,r5                /* round low to line bdy */
246         subf    r8,r6,r4                /* compute length */
247         add     r8,r8,r5                /* ensure we get enough */
248         lwz     r9,DCACHEL1LOGLINESIZE(r10)     /* Get log-2 of dcache line size */
249         srw.    r8,r8,r9                /* compute line count */
250         beqlr                           /* nothing to do? */
251         mfmsr   r5                      /* Disable MMU Data Relocation */
252         ori     r0,r5,MSR_DR
253         xori    r0,r0,MSR_DR
254         sync
255         mtmsr   r0
256         sync
257         isync
258         mtctr   r8
259 0:      dcbst   0,r6
260         add     r6,r6,r7
261         bdnz    0b
262         sync
263         isync
264         mtmsr   r5                      /* Re-enable MMU Data Relocation */
265         sync
266         isync
267         blr
268
269 _GLOBAL(flush_inval_dcache_range)
270         ld      r10,PPC64_CACHES@toc(r2)
271         lwz     r7,DCACHEL1LINESIZE(r10)        /* Get dcache line size */
272         addi    r5,r7,-1
273         andc    r6,r3,r5                /* round low to line bdy */
274         subf    r8,r6,r4                /* compute length */
275         add     r8,r8,r5                /* ensure we get enough */
276         lwz     r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
277         srw.    r8,r8,r9                /* compute line count */
278         beqlr                           /* nothing to do? */
279         sync
280         isync
281         mtctr   r8
282 0:      dcbf    0,r6
283         add     r6,r6,r7
284         bdnz    0b
285         sync
286         isync
287         blr
288
289
290 /*
291  * Flush a particular page from the data cache to RAM.
292  * Note: this is necessary because the instruction cache does *not*
293  * snoop from the data cache.
294  *
295  *      void __flush_dcache_icache(void *page)
296  */
297 _GLOBAL(__flush_dcache_icache)
298 /*
299  * Flush the data cache to memory 
300  * 
301  * Different systems have different cache line sizes
302  */
303
304 /* Flush the dcache */
305         ld      r7,PPC64_CACHES@toc(r2)
306         clrrdi  r3,r3,PAGE_SHIFT                    /* Page align */
307         lwz     r4,DCACHEL1LINESPERPAGE(r7)     /* Get # dcache lines per page */
308         lwz     r5,DCACHEL1LINESIZE(r7)         /* Get dcache line size */
309         mr      r6,r3
310         mtctr   r4
311 0:      dcbst   0,r6
312         add     r6,r6,r5
313         bdnz    0b
314         sync
315
316 /* Now invalidate the icache */ 
317
318         lwz     r4,ICACHEL1LINESPERPAGE(r7)     /* Get # icache lines per page */
319         lwz     r5,ICACHEL1LINESIZE(r7)         /* Get icache line size */
320         mtctr   r4
321 1:      icbi    0,r3
322         add     r3,r3,r5
323         bdnz    1b
324         isync
325         blr
326         
327 /*
328  * I/O string operations
329  *
330  * insb(port, buf, len)
331  * outsb(port, buf, len)
332  * insw(port, buf, len)
333  * outsw(port, buf, len)
334  * insl(port, buf, len)
335  * outsl(port, buf, len)
336  * insw_ns(port, buf, len)
337  * outsw_ns(port, buf, len)
338  * insl_ns(port, buf, len)
339  * outsl_ns(port, buf, len)
340  *
341  * The *_ns versions don't do byte-swapping.
342  */
343 _GLOBAL(_insb)
344         cmpwi   0,r5,0
345         mtctr   r5
346         subi    r4,r4,1
347         blelr-
348 00:     lbz     r5,0(r3)
349         eieio
350         stbu    r5,1(r4)
351         bdnz    00b
352         twi     0,r5,0
353         isync
354         blr
355
356 _GLOBAL(_outsb)
357         cmpwi   0,r5,0
358         mtctr   r5
359         subi    r4,r4,1
360         blelr-
361 00:     lbzu    r5,1(r4)
362         stb     r5,0(r3)
363         bdnz    00b
364         sync
365         blr     
366
367 _GLOBAL(_insw)
368         cmpwi   0,r5,0
369         mtctr   r5
370         subi    r4,r4,2
371         blelr-
372 00:     lhbrx   r5,0,r3
373         eieio
374         sthu    r5,2(r4)
375         bdnz    00b
376         twi     0,r5,0
377         isync
378         blr
379
380 _GLOBAL(_outsw)
381         cmpwi   0,r5,0
382         mtctr   r5
383         subi    r4,r4,2
384         blelr-
385 00:     lhzu    r5,2(r4)
386         sthbrx  r5,0,r3 
387         bdnz    00b
388         sync
389         blr     
390
391 _GLOBAL(_insl)
392         cmpwi   0,r5,0
393         mtctr   r5
394         subi    r4,r4,4
395         blelr-
396 00:     lwbrx   r5,0,r3
397         eieio
398         stwu    r5,4(r4)
399         bdnz    00b
400         twi     0,r5,0
401         isync
402         blr
403
404 _GLOBAL(_outsl)
405         cmpwi   0,r5,0
406         mtctr   r5
407         subi    r4,r4,4
408         blelr-
409 00:     lwzu    r5,4(r4)
410         stwbrx  r5,0,r3
411         bdnz    00b
412         sync
413         blr     
414
415 /* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */
416 _GLOBAL(_insw_ns)
417         cmpwi   0,r5,0
418         mtctr   r5
419         subi    r4,r4,2
420         blelr-
421 00:     lhz     r5,0(r3)
422         eieio
423         sthu    r5,2(r4)
424         bdnz    00b
425         twi     0,r5,0
426         isync
427         blr
428
429 /* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */
430 _GLOBAL(_outsw_ns)
431         cmpwi   0,r5,0
432         mtctr   r5
433         subi    r4,r4,2
434         blelr-
435 00:     lhzu    r5,2(r4)
436         sth     r5,0(r3)
437         bdnz    00b
438         sync
439         blr     
440
441 _GLOBAL(_insl_ns)
442         cmpwi   0,r5,0
443         mtctr   r5
444         subi    r4,r4,4
445         blelr-
446 00:     lwz     r5,0(r3)
447         eieio
448         stwu    r5,4(r4)
449         bdnz    00b
450         twi     0,r5,0
451         isync
452         blr
453
454 _GLOBAL(_outsl_ns)
455         cmpwi   0,r5,0
456         mtctr   r5
457         subi    r4,r4,4
458         blelr-
459 00:     lwzu    r5,4(r4)
460         stw     r5,0(r3)
461         bdnz    00b
462         sync
463         blr     
464
465 /*
466  * identify_cpu and calls setup_cpu
467  * In:  r3 = base of the cpu_specs array
468  *      r4 = address of cur_cpu_spec
469  *      r5 = relocation offset
470  */
471 _GLOBAL(identify_cpu)
472         mfpvr   r7
473 1:
474         lwz     r8,CPU_SPEC_PVR_MASK(r3)
475         and     r8,r8,r7
476         lwz     r9,CPU_SPEC_PVR_VALUE(r3)
477         cmplw   0,r9,r8
478         beq     1f
479         addi    r3,r3,CPU_SPEC_ENTRY_SIZE
480         b       1b
481 1:
482         sub     r0,r3,r5
483         std     r0,0(r4)
484         ld      r4,CPU_SPEC_SETUP(r3)
485         add     r4,r4,r5
486         ld      r4,0(r4)
487         add     r4,r4,r5
488         mtctr   r4
489         /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */
490         mr      r4,r3
491         mr      r3,r5
492         bctr
493
494 /*
495  * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
496  * and writes nop's over sections of code that don't apply for this cpu.
497  * r3 = data offset (not changed)
498  */
499 _GLOBAL(do_cpu_ftr_fixups)
500         /* Get CPU 0 features */
501         LOADADDR(r6,cur_cpu_spec)
502         sub     r6,r6,r3
503         ld      r4,0(r6)
504         sub     r4,r4,r3
505         ld      r4,CPU_SPEC_FEATURES(r4)
506         /* Get the fixup table */
507         LOADADDR(r6,__start___ftr_fixup)
508         sub     r6,r6,r3
509         LOADADDR(r7,__stop___ftr_fixup)
510         sub     r7,r7,r3
511         /* Do the fixup */
512 1:      cmpld   r6,r7
513         bgelr
514         addi    r6,r6,32
515         ld      r8,-32(r6)      /* mask */
516         and     r8,r8,r4
517         ld      r9,-24(r6)      /* value */
518         cmpld   r8,r9
519         beq     1b
520         ld      r8,-16(r6)      /* section begin */
521         ld      r9,-8(r6)       /* section end */
522         subf.   r9,r8,r9
523         beq     1b
524         /* write nops over the section of code */
525         /* todo: if large section, add a branch at the start of it */
526         srwi    r9,r9,2
527         mtctr   r9
528         sub     r8,r8,r3
529         lis     r0,0x60000000@h /* nop */
530 3:      stw     r0,0(r8)
531         andi.   r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
532         beq     2f
533         dcbst   0,r8            /* suboptimal, but simpler */
534         sync
535         icbi    0,r8
536 2:      addi    r8,r8,4
537         bdnz    3b
538         sync                    /* additional sync needed on g4 */
539         isync
540         b       1b
541
542 #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
543 /*
544  * Do an IO access in real mode
545  */
546 _GLOBAL(real_readb)
547         mfmsr   r7
548         ori     r0,r7,MSR_DR
549         xori    r0,r0,MSR_DR
550         sync
551         mtmsrd  r0
552         sync
553         isync
554         mfspr   r6,SPRN_HID4
555         rldicl  r5,r6,32,0
556         ori     r5,r5,0x100
557         rldicl  r5,r5,32,0
558         sync
559         mtspr   SPRN_HID4,r5
560         isync
561         slbia
562         isync
563         lbz     r3,0(r3)
564         sync
565         mtspr   SPRN_HID4,r6
566         isync
567         slbia
568         isync
569         mtmsrd  r7
570         sync
571         isync
572         blr
573
574         /*
575  * Do an IO access in real mode
576  */
577 _GLOBAL(real_writeb)
578         mfmsr   r7
579         ori     r0,r7,MSR_DR
580         xori    r0,r0,MSR_DR
581         sync
582         mtmsrd  r0
583         sync
584         isync
585         mfspr   r6,SPRN_HID4
586         rldicl  r5,r6,32,0
587         ori     r5,r5,0x100
588         rldicl  r5,r5,32,0
589         sync
590         mtspr   SPRN_HID4,r5
591         isync
592         slbia
593         isync
594         stb     r3,0(r4)
595         sync
596         mtspr   SPRN_HID4,r6
597         isync
598         slbia
599         isync
600         mtmsrd  r7
601         sync
602         isync
603         blr
604 #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
605
606 /*
607  * Create a kernel thread
608  *   kernel_thread(fn, arg, flags)
609  */
610 _GLOBAL(kernel_thread)
611         std     r29,-24(r1)
612         std     r30,-16(r1)
613         stdu    r1,-STACK_FRAME_OVERHEAD(r1)
614         mr      r29,r3
615         mr      r30,r4
616         ori     r3,r5,CLONE_VM  /* flags */
617         oris    r3,r3,(CLONE_UNTRACED>>16)
618         li      r4,0            /* new sp (unused) */
619         li      r0,__NR_clone
620         sc
621         cmpdi   0,r3,0          /* parent or child? */
622         bne     1f              /* return if parent */
623         li      r0,0
624         stdu    r0,-STACK_FRAME_OVERHEAD(r1)
625         ld      r2,8(r29)
626         ld      r29,0(r29)
627         mtlr    r29              /* fn addr in lr */
628         mr      r3,r30          /* load arg and call fn */
629         blrl
630         li      r0,__NR_exit    /* exit after child exits */
631         li      r3,0
632         sc
633 1:      addi    r1,r1,STACK_FRAME_OVERHEAD      
634         ld      r29,-24(r1)
635         ld      r30,-16(r1)
636         blr
637
638 /*
639  * disable_kernel_fp()
640  * Disable the FPU.
641  */
642 _GLOBAL(disable_kernel_fp)
643         mfmsr   r3
644         rldicl  r0,r3,(63-MSR_FP_LG),1
645         rldicl  r3,r0,(MSR_FP_LG+1),0
646         mtmsrd  r3                      /* disable use of fpu now */
647         isync
648         blr
649
650 #ifdef CONFIG_ALTIVEC
651
652 #if 0 /* this has no callers for now */
653 /*
654  * disable_kernel_altivec()
655  * Disable the VMX.
656  */
657 _GLOBAL(disable_kernel_altivec)
658         mfmsr   r3
659         rldicl  r0,r3,(63-MSR_VEC_LG),1
660         rldicl  r3,r0,(MSR_VEC_LG+1),0
661         mtmsrd  r3                      /* disable use of VMX now */
662         isync
663         blr
664 #endif /* 0 */
665
666 /*
667  * giveup_altivec(tsk)
668  * Disable VMX for the task given as the argument,
669  * and save the vector registers in its thread_struct.
670  * Enables the VMX for use in the kernel on return.
671  */
672 _GLOBAL(giveup_altivec)
673         mfmsr   r5
674         oris    r5,r5,MSR_VEC@h
675         mtmsrd  r5                      /* enable use of VMX now */
676         isync
677         cmpdi   0,r3,0
678         beqlr-                          /* if no previous owner, done */
679         addi    r3,r3,THREAD            /* want THREAD of task */
680         ld      r5,PT_REGS(r3)
681         cmpdi   0,r5,0
682         SAVE_32VRS(0,r4,r3)
683         mfvscr  vr0
684         li      r4,THREAD_VSCR
685         stvx    vr0,r4,r3
686         beq     1f
687         ld      r4,_MSR-STACK_FRAME_OVERHEAD(r5)
688         lis     r3,MSR_VEC@h
689         andc    r4,r4,r3                /* disable FP for previous task */
690         std     r4,_MSR-STACK_FRAME_OVERHEAD(r5)
691 1:
692 #ifndef CONFIG_SMP
693         li      r5,0
694         ld      r4,last_task_used_altivec@got(r2)
695         std     r5,0(r4)
696 #endif /* CONFIG_SMP */
697         blr
698
699 #endif /* CONFIG_ALTIVEC */
700
701 _GLOBAL(__setup_cpu_power3)
702         blr
703
704 _GLOBAL(execve)
705         li      r0,__NR_execve
706         sc
707         bnslr
708         neg     r3,r3
709         blr
710
711 /* kexec_wait(phys_cpu)
712  *
713  * wait for the flag to change, indicating this kernel is going away but
714  * the slave code for the next one is at addresses 0 to 100.
715  *
716  * This is used by all slaves.
717  *
718  * Physical (hardware) cpu id should be in r3.
719  */
720 _GLOBAL(kexec_wait)
721         bl      1f
722 1:      mflr    r5
723         addi    r5,r5,kexec_flag-1b
724
725 99:     HMT_LOW
726 #ifdef CONFIG_KEXEC             /* use no memory without kexec */
727         lwz     r4,0(r5)
728         cmpwi   0,r4,0
729         bnea    0x60
730 #endif
731         b       99b
732
733 /* this can be in text because we won't change it until we are
734  * running in real anyways
735  */
736 kexec_flag:
737         .long   0
738
739
740 #ifdef CONFIG_KEXEC
741
742 /* kexec_smp_wait(void)
743  *
744  * call with interrupts off
745  * note: this is a terminal routine, it does not save lr
746  *
747  * get phys id from paca
748  * set paca id to -1 to say we got here
749  * switch to real mode
750  * join other cpus in kexec_wait(phys_id)
751  */
752 _GLOBAL(kexec_smp_wait)
753         lhz     r3,PACAHWCPUID(r13)
754         li      r4,-1
755         sth     r4,PACAHWCPUID(r13)     /* let others know we left */
756         bl      real_mode
757         b       .kexec_wait
758
759 /*
760  * switch to real mode (turn mmu off)
761  * we use the early kernel trick that the hardware ignores bits
762  * 0 and 1 (big endian) of the effective address in real mode
763  *
764  * don't overwrite r3 here, it is live for kexec_wait above.
765  */
766 real_mode:      /* assume normal blr return */
767 1:      li      r9,MSR_RI
768         li      r10,MSR_DR|MSR_IR
769         mflr    r11             /* return address to SRR0 */
770         mfmsr   r12
771         andc    r9,r12,r9
772         andc    r10,r12,r10
773
774         mtmsrd  r9,1
775         mtspr   SPRN_SRR1,r10
776         mtspr   SPRN_SRR0,r11
777         rfid
778
779
780 /*
781  * kexec_sequence(newstack, start, image, control, clear_all())
782  *
783  * does the grungy work with stack switching and real mode switches
784  * also does simple calls to other code
785  */
786
787 _GLOBAL(kexec_sequence)
788         mflr    r0
789         std     r0,16(r1)
790
791         /* switch stacks to newstack -- &kexec_stack.stack */
792         stdu    r1,THREAD_SIZE-112(r3)
793         mr      r1,r3
794
795         li      r0,0
796         std     r0,16(r1)
797
798         /* save regs for local vars on new stack.
799          * yes, we won't go back, but ...
800          */
801         std     r31,-8(r1)
802         std     r30,-16(r1)
803         std     r29,-24(r1)
804         std     r28,-32(r1)
805         std     r27,-40(r1)
806         std     r26,-48(r1)
807         std     r25,-56(r1)
808
809         stdu    r1,-112-64(r1)
810
811         /* save args into preserved regs */
812         mr      r31,r3                  /* newstack (both) */
813         mr      r30,r4                  /* start (real) */
814         mr      r29,r5                  /* image (virt) */
815         mr      r28,r6                  /* control, unused */
816         mr      r27,r7                  /* clear_all() fn desc */
817         mr      r26,r8                  /* spare */
818         lhz     r25,PACAHWCPUID(r13)    /* get our phys cpu from paca */
819
820         /* disable interrupts, we are overwriting kernel data next */
821         mfmsr   r3
822         rlwinm  r3,r3,0,17,15
823         mtmsrd  r3,1
824
825         /* copy dest pages, flush whole dest image */
826         mr      r3,r29
827         bl      .kexec_copy_flush       /* (image) */
828
829         /* turn off mmu */
830         bl      real_mode
831
832         /* clear out hardware hash page table and tlb */
833         ld      r5,0(r27)               /* deref function descriptor */
834         mtctr   r5
835         bctrl                           /* ppc_md.hash_clear_all(void); */
836
837 /*
838  *   kexec image calling is:
839  *      the first 0x100 bytes of the entry point are copied to 0
840  *
841  *      all slaves branch to slave = 0x60 (absolute)
842  *              slave(phys_cpu_id);
843  *
844  *      master goes to start = entry point
845  *              start(phys_cpu_id, start, 0);
846  *
847  *
848  *   a wrapper is needed to call existing kernels, here is an approximate
849  *   description of one method:
850  *
851  * v2: (2.6.10)
852  *   start will be near the boot_block (maybe 0x100 bytes before it?)
853  *   it will have a 0x60, which will b to boot_block, where it will wait
854  *   and 0 will store phys into struct boot-block and load r3 from there,
855  *   copy kernel 0-0x100 and tell slaves to back down to 0x60 again
856  *
857  * v1: (2.6.9)
858  *    boot block will have all cpus scanning device tree to see if they
859  *    are the boot cpu ?????
860  *    other device tree differences (prop sizes, va vs pa, etc)...
861  */
862
863         /* copy  0x100 bytes starting at start to 0 */
864         li      r3,0
865         mr      r4,r30
866         li      r5,0x100
867         li      r6,0
868         bl      .copy_and_flush /* (dest, src, copy limit, start offset) */
869 1:      /* assume normal blr return */
870
871         /* release other cpus to the new kernel secondary start at 0x60 */
872         mflr    r5
873         li      r6,1
874         stw     r6,kexec_flag-1b(5)
875         mr      r3,r25  # my phys cpu
876         mr      r4,r30  # start, aka phys mem offset
877         mtlr    4
878         li      r5,0
879         blr     /* image->start(physid, image->start, 0); */
880 #endif /* CONFIG_KEXEC */