Merge branch 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ickle...
[pandora-kernel.git] / arch / tile / kernel / relocate_kernel.S
1 /*
2  * Copyright 2010 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  *
14  * copy new kernel into place and then call hv_reexec
15  *
16  */
17
18 #include <linux/linkage.h>
19 #include <arch/chip.h>
20 #include <asm/page.h>
21 #include <hv/hypervisor.h>
22
23 #define ___hvb  MEM_SV_INTRPT + HV_GLUE_START_CPA
24
25 #define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f))
26
27 #define ___hv_console_putc ___hv_dispatch(HV_DISPATCH_CONSOLE_PUTC)
28 #define ___hv_halt         ___hv_dispatch(HV_DISPATCH_HALT)
29 #define ___hv_reexec       ___hv_dispatch(HV_DISPATCH_REEXEC)
30 #define ___hv_flush_remote ___hv_dispatch(HV_DISPATCH_FLUSH_REMOTE)
31
32 #undef RELOCATE_NEW_KERNEL_VERBOSE
33
34 STD_ENTRY(relocate_new_kernel)
35
36         move    r30, r0         /* page list */
37         move    r31, r1         /* address of page we are on */
38         move    r32, r2         /* start address of new kernel */
39
40         shri    r1, r1, PAGE_SHIFT
41         addi    r1, r1, 1
42         shli    sp, r1, PAGE_SHIFT
43         addi    sp, sp, -8
44         /* we now have a stack (whether we need one or not) */
45
46         moveli  r40, lo16(___hv_console_putc)
47         auli    r40, r40, ha16(___hv_console_putc)
48
49 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
50         moveli  r0, 'r'
51         jalr    r40
52
53         moveli  r0, '_'
54         jalr    r40
55
56         moveli  r0, 'n'
57         jalr    r40
58
59         moveli  r0, '_'
60         jalr    r40
61
62         moveli  r0, 'k'
63         jalr    r40
64
65         moveli  r0, '\n'
66         jalr    r40
67 #endif
68
69         /*
70          * Throughout this code r30 is pointer to the element of page
71          * list we are working on.
72          *
73          * Normally we get to the next element of the page list by
74          * incrementing r30 by four.  The exception is if the element
75          * on the page list is an IND_INDIRECTION in which case we use
76          * the element with the low bits masked off as the new value
77          * of r30.
78          *
79          * To get this started, we need the value passed to us (which
80          * will always be an IND_INDIRECTION) in memory somewhere with
81          * r30 pointing at it.  To do that, we push the value passed
82          * to us on the stack and make r30 point to it.
83          */
84
85         sw      sp, r30
86         move    r30, sp
87         addi    sp, sp, -8
88
89 #if CHIP_HAS_CBOX_HOME_MAP()
90         /*
91          * On TILEPro, we need to flush all tiles' caches, since we may
92          * have been doing hash-for-home caching there.  Note that we
93          * must do this _after_ we're completely done modifying any memory
94          * other than our output buffer (which we know is locally cached).
95          * We want the caches to be fully clean when we do the reexec,
96          * because the hypervisor is going to do this flush again at that
97          * point, and we don't want that second flush to overwrite any memory.
98          */
99         {
100          move   r0, zero         /* cache_pa */
101          move   r1, zero
102         }
103         {
104          auli   r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
105          movei  r3, -1           /* cache_cpumask; -1 means all client tiles */
106         }
107         {
108          move   r4, zero         /* tlb_va */
109          move   r5, zero         /* tlb_length */
110         }
111         {
112          move   r6, zero         /* tlb_pgsize */
113          move   r7, zero         /* tlb_cpumask */
114         }
115         {
116          move   r8, zero         /* asids */
117          moveli r20, lo16(___hv_flush_remote)
118         }
119         {
120          move   r9, zero         /* asidcount */
121          auli   r20, r20, ha16(___hv_flush_remote)
122         }
123
124         jalr    r20
125 #endif
126
127         /* r33 is destination pointer, default to zero */
128
129         moveli  r33, 0
130
131 .Lloop: lw      r10, r30
132
133         andi    r9, r10, 0xf    /* low 4 bits tell us what type it is */
134         xor     r10, r10, r9    /* r10 is now value with low 4 bits stripped */
135
136         seqi    r0, r9, 0x1     /* IND_DESTINATION */
137         bzt     r0, .Ltry2
138
139         move    r33, r10
140
141 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
142         moveli  r0, 'd'
143         jalr    r40
144 #endif
145
146         addi    r30, r30, 4
147         j       .Lloop
148
149 .Ltry2:
150         seqi    r0, r9, 0x2     /* IND_INDIRECTION */
151         bzt     r0, .Ltry4
152
153         move    r30, r10
154
155 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
156         moveli  r0, 'i'
157         jalr    r40
158 #endif
159
160         j       .Lloop
161
162 .Ltry4:
163         seqi    r0, r9, 0x4     /* IND_DONE */
164         bzt     r0, .Ltry8
165
166         mf
167
168 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
169         moveli  r0, 'D'
170         jalr    r40
171         moveli  r0, '\n'
172         jalr    r40
173 #endif
174
175         move    r0, r32
176         moveli  r1, 0           /* arg to hv_reexec is 64 bits */
177
178         moveli  r41, lo16(___hv_reexec)
179         auli    r41, r41, ha16(___hv_reexec)
180
181         jalr    r41
182
183         /* we should not get here */
184
185         moveli  r0, '?'
186         jalr    r40
187         moveli  r0, '\n'
188         jalr    r40
189
190         j       .Lhalt
191
192 .Ltry8: seqi    r0, r9, 0x8     /* IND_SOURCE */
193         bz      r0, .Lerr       /* unknown type */
194
195         /* copy page at r10 to page at r33 */
196
197         move    r11, r33
198
199         moveli  r0, lo16(PAGE_SIZE)
200         auli    r0, r0, ha16(PAGE_SIZE)
201         add     r33, r33, r0
202
203         /* copy word at r10 to word at r11 until r11 equals r33 */
204
205         /* We know page size must be multiple of 16, so we can unroll
206          * 16 times safely without any edge case checking.
207          *
208          * Issue a flush of the destination every 16 words to avoid
209          * incoherence when starting the new kernel.  (Now this is
210          * just good paranoia because the hv_reexec call will also
211          * take care of this.)
212          */
213
214 1:
215         { lw    r0, r10; addi   r10, r10, 4 }
216         { sw    r11, r0; addi   r11, r11, 4 }
217         { lw    r0, r10; addi   r10, r10, 4 }
218         { sw    r11, r0; addi   r11, r11, 4 }
219         { lw    r0, r10; addi   r10, r10, 4 }
220         { sw    r11, r0; addi   r11, r11, 4 }
221         { lw    r0, r10; addi   r10, r10, 4 }
222         { sw    r11, r0; addi   r11, r11, 4 }
223         { lw    r0, r10; addi   r10, r10, 4 }
224         { sw    r11, r0; addi   r11, r11, 4 }
225         { lw    r0, r10; addi   r10, r10, 4 }
226         { sw    r11, r0; addi   r11, r11, 4 }
227         { lw    r0, r10; addi   r10, r10, 4 }
228         { sw    r11, r0; addi   r11, r11, 4 }
229         { lw    r0, r10; addi   r10, r10, 4 }
230         { sw    r11, r0; addi   r11, r11, 4 }
231         { lw    r0, r10; addi   r10, r10, 4 }
232         { sw    r11, r0; addi   r11, r11, 4 }
233         { lw    r0, r10; addi   r10, r10, 4 }
234         { sw    r11, r0; addi   r11, r11, 4 }
235         { lw    r0, r10; addi   r10, r10, 4 }
236         { sw    r11, r0; addi   r11, r11, 4 }
237         { lw    r0, r10; addi   r10, r10, 4 }
238         { sw    r11, r0; addi   r11, r11, 4 }
239         { lw    r0, r10; addi   r10, r10, 4 }
240         { sw    r11, r0; addi   r11, r11, 4 }
241         { lw    r0, r10; addi   r10, r10, 4 }
242         { sw    r11, r0; addi   r11, r11, 4 }
243         { lw    r0, r10; addi   r10, r10, 4 }
244         { sw    r11, r0; addi   r11, r11, 4 }
245         { lw    r0, r10; addi   r10, r10, 4 }
246         { sw    r11, r0 }
247         { flush r11    ; addi   r11, r11, 4 }
248
249         seq     r0, r33, r11
250         bzt     r0, 1b
251
252 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
253         moveli  r0, 's'
254         jalr    r40
255 #endif
256
257         addi    r30, r30, 4
258         j       .Lloop
259
260
261 .Lerr:  moveli  r0, 'e'
262         jalr    r40
263         moveli  r0, 'r'
264         jalr    r40
265         moveli  r0, 'r'
266         jalr    r40
267         moveli  r0, '\n'
268         jalr    r40
269 .Lhalt:
270         moveli  r41, lo16(___hv_halt)
271         auli    r41, r41, ha16(___hv_halt)
272
273         jalr    r41
274         STD_ENDPROC(relocate_new_kernel)
275
276         .section .rodata,"a"
277
278         .globl relocate_new_kernel_size
279 relocate_new_kernel_size:
280         .long .Lend_relocate_new_kernel - relocate_new_kernel