Merge tag 'for-3.8-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[linux-drm-fsl-dcu.git] / arch / mips / kernel / relocate_kernel.S
1 /*
2  * relocate_kernel.S for kexec
3  * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
4  *
5  * This source code is licensed under the GNU General Public License,
6  * Version 2.  See the file COPYING for more details.
7  */
8
9 #include <asm/asm.h>
10 #include <asm/asmmacro.h>
11 #include <asm/regdef.h>
12 #include <asm/page.h>
13 #include <asm/mipsregs.h>
14 #include <asm/stackframe.h>
15 #include <asm/addrspace.h>
16
17 LEAF(relocate_new_kernel)
18         PTR_L a0,       arg0
19         PTR_L a1,       arg1
20         PTR_L a2,       arg2
21         PTR_L a3,       arg3
22
23         PTR_L           s0, kexec_indirection_page
24         PTR_L           s1, kexec_start_address
25
26 process_entry:
27         PTR_L           s2, (s0)
28         PTR_ADD         s0, s0, SZREG
29
30         /* destination page */
31         and             s3, s2, 0x1
32         beq             s3, zero, 1f
33         and             s4, s2, ~0x1    /* store destination addr in s4 */
34         b               process_entry
35
36 1:
37         /* indirection page, update s0  */
38         and             s3, s2, 0x2
39         beq             s3, zero, 1f
40         and             s0, s2, ~0x2
41         b               process_entry
42
43 1:
44         /* done page */
45         and             s3, s2, 0x4
46         beq             s3, zero, 1f
47         b               done
48 1:
49         /* source page */
50         and             s3, s2, 0x8
51         beq             s3, zero, process_entry
52         and             s2, s2, ~0x8
53         li              s6, (1 << PAGE_SHIFT) / SZREG
54
55 copy_word:
56         /* copy page word by word */
57         REG_L           s5, (s2)
58         REG_S           s5, (s4)
59         PTR_ADD         s4, s4, SZREG
60         PTR_ADD         s2, s2, SZREG
61         LONG_SUB        s6, s6, 1
62         beq             s6, zero, process_entry
63         b               copy_word
64         b               process_entry
65
66 done:
67 #ifdef CONFIG_SMP
68         /* kexec_flag reset is signal to other CPUs what kernel
69            was moved to it's location. Note - we need relocated address
70            of kexec_flag.  */
71
72         bal             1f
73  1:     move            t1,ra;
74         PTR_LA          t2,1b
75         PTR_LA          t0,kexec_flag
76         PTR_SUB         t0,t0,t2;
77         PTR_ADD         t0,t1,t0;
78         LONG_S          zero,(t0)
79 #endif
80
81 #ifdef CONFIG_CPU_CAVIUM_OCTEON
82         /* We need to flush I-cache before jumping to new kernel.
83          * Unfortunatelly, this code is cpu-specific.
84          */
85         .set push
86         .set noreorder
87         syncw
88         syncw
89         synci           0($0)
90         .set pop
91 #else
92         sync
93 #endif
94         /* jump to kexec_start_address */
95         j               s1
96         END(relocate_new_kernel)
97
98 #ifdef CONFIG_SMP
99 /*
100  * Other CPUs should wait until code is relocated and
101  * then start at entry (?) point.
102  */
103 LEAF(kexec_smp_wait)
104         PTR_L           a0, s_arg0
105         PTR_L           a1, s_arg1
106         PTR_L           a2, s_arg2
107         PTR_L           a3, s_arg3
108         PTR_L           s1, kexec_start_address
109
110         /* Non-relocated address works for args and kexec_start_address ( old
111          * kernel is not overwritten). But we need relocated address of
112          * kexec_flag.
113          */
114
115         bal             1f
116 1:      move            t1,ra;
117         PTR_LA          t2,1b
118         PTR_LA          t0,kexec_flag
119         PTR_SUB         t0,t0,t2;
120         PTR_ADD         t0,t1,t0;
121
122 1:      LONG_L          s0, (t0)
123         bne             s0, zero,1b
124
125 #ifdef CONFIG_CPU_CAVIUM_OCTEON
126         .set push
127         .set noreorder
128         synci           0($0)
129         .set pop
130 #else
131         sync
132 #endif
133         j               s1
134         END(kexec_smp_wait)
135 #endif
136
137 #ifdef __mips64
138        /* all PTR's must be aligned to 8 byte in 64-bit mode */
139        .align  3
140 #endif
141
142 /* All parameters to new kernel are passed in registers a0-a3.
143  * kexec_args[0..3] are uses to prepare register values.
144  */
145
146 kexec_args:
147         EXPORT(kexec_args)
148 arg0:   PTR             0x0
149 arg1:   PTR             0x0
150 arg2:   PTR             0x0
151 arg3:   PTR             0x0
152         .size   kexec_args,PTRSIZE*4
153
154 #ifdef CONFIG_SMP
155 /*
156  * Secondary CPUs may have different kernel parameters in
157  * their registers a0-a3. secondary_kexec_args[0..3] are used
158  * to prepare register values.
159  */
160 secondary_kexec_args:
161         EXPORT(secondary_kexec_args)
162 s_arg0: PTR             0x0
163 s_arg1: PTR             0x0
164 s_arg2: PTR             0x0
165 s_arg3: PTR             0x0
166         .size   secondary_kexec_args,PTRSIZE*4
167 kexec_flag:
168         LONG            0x1
169
170 #endif
171
172 kexec_start_address:
173         EXPORT(kexec_start_address)
174         PTR             0x0
175         .size           kexec_start_address, PTRSIZE
176
177 kexec_indirection_page:
178         EXPORT(kexec_indirection_page)
179         PTR             0
180         .size           kexec_indirection_page, PTRSIZE
181
182 relocate_new_kernel_end:
183
184 relocate_new_kernel_size:
185         EXPORT(relocate_new_kernel_size)
186         PTR             relocate_new_kernel_end - relocate_new_kernel
187         .size           relocate_new_kernel_size, PTRSIZE