mm: fix exec activate_mm vs TLB shootdown and lazy tlb switching race
[linux/fpc-iii.git] / arch / tile / kernel / relocate_kernel_32.S
blobe44fbcf8cbd5d22748791efe0b6606d32426d387
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  */
18 #include <linux/linkage.h>
19 #include <arch/chip.h>
20 #include <asm/page.h>
21 #include <hv/hypervisor.h>
23 #undef RELOCATE_NEW_KERNEL_VERBOSE
25 STD_ENTRY(relocate_new_kernel)
27         move    r30, r0         /* page list */
28         move    r31, r1         /* address of page we are on */
29         move    r32, r2         /* start address of new kernel */
31         shri    r1, r1, PAGE_SHIFT
32         addi    r1, r1, 1
33         shli    sp, r1, PAGE_SHIFT
34         addi    sp, sp, -8
35         /* we now have a stack (whether we need one or not) */
37         moveli  r40, lo16(hv_console_putc)
38         auli    r40, r40, ha16(hv_console_putc)
40 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
41         moveli  r0, 'r'
42         jalr    r40
44         moveli  r0, '_'
45         jalr    r40
47         moveli  r0, 'n'
48         jalr    r40
50         moveli  r0, '_'
51         jalr    r40
53         moveli  r0, 'k'
54         jalr    r40
56         moveli  r0, '\n'
57         jalr    r40
58 #endif
60         /*
61          * Throughout this code r30 is pointer to the element of page
62          * list we are working on.
63          *
64          * Normally we get to the next element of the page list by
65          * incrementing r30 by four.  The exception is if the element
66          * on the page list is an IND_INDIRECTION in which case we use
67          * the element with the low bits masked off as the new value
68          * of r30.
69          *
70          * To get this started, we need the value passed to us (which
71          * will always be an IND_INDIRECTION) in memory somewhere with
72          * r30 pointing at it.  To do that, we push the value passed
73          * to us on the stack and make r30 point to it.
74          */
76         sw      sp, r30
77         move    r30, sp
78         addi    sp, sp, -8
80         /*
81          * On TILEPro, we need to flush all tiles' caches, since we may
82          * have been doing hash-for-home caching there.  Note that we
83          * must do this _after_ we're completely done modifying any memory
84          * other than our output buffer (which we know is locally cached).
85          * We want the caches to be fully clean when we do the reexec,
86          * because the hypervisor is going to do this flush again at that
87          * point, and we don't want that second flush to overwrite any memory.
88          */
89         {
90          move   r0, zero         /* cache_pa */
91          move   r1, zero
92         }
93         {
94          auli   r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
95          movei  r3, -1           /* cache_cpumask; -1 means all client tiles */
96         }
97         {
98          move   r4, zero         /* tlb_va */
99          move   r5, zero         /* tlb_length */
100         }
101         {
102          move   r6, zero         /* tlb_pgsize */
103          move   r7, zero         /* tlb_cpumask */
104         }
105         {
106          move   r8, zero         /* asids */
107          moveli r20, lo16(hv_flush_remote)
108         }
109         {
110          move   r9, zero         /* asidcount */
111          auli   r20, r20, ha16(hv_flush_remote)
112         }
114         jalr    r20
116         /* r33 is destination pointer, default to zero */
118         moveli  r33, 0
120 .Lloop: lw      r10, r30
122         andi    r9, r10, 0xf    /* low 4 bits tell us what type it is */
123         xor     r10, r10, r9    /* r10 is now value with low 4 bits stripped */
125         seqi    r0, r9, 0x1     /* IND_DESTINATION */
126         bzt     r0, .Ltry2
128         move    r33, r10
130 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
131         moveli  r0, 'd'
132         jalr    r40
133 #endif
135         addi    r30, r30, 4
136         j       .Lloop
138 .Ltry2:
139         seqi    r0, r9, 0x2     /* IND_INDIRECTION */
140         bzt     r0, .Ltry4
142         move    r30, r10
144 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
145         moveli  r0, 'i'
146         jalr    r40
147 #endif
149         j       .Lloop
151 .Ltry4:
152         seqi    r0, r9, 0x4     /* IND_DONE */
153         bzt     r0, .Ltry8
155         mf
157 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
158         moveli  r0, 'D'
159         jalr    r40
160         moveli  r0, '\n'
161         jalr    r40
162 #endif
164         move    r0, r32
165         moveli  r1, 0           /* arg to hv_reexec is 64 bits */
167         moveli  r41, lo16(hv_reexec)
168         auli    r41, r41, ha16(hv_reexec)
170         jalr    r41
172         /* we should not get here */
174         moveli  r0, '?'
175         jalr    r40
176         moveli  r0, '\n'
177         jalr    r40
179         j       .Lhalt
181 .Ltry8: seqi    r0, r9, 0x8     /* IND_SOURCE */
182         bz      r0, .Lerr       /* unknown type */
184         /* copy page at r10 to page at r33 */
186         move    r11, r33
188         moveli  r0, lo16(PAGE_SIZE)
189         auli    r0, r0, ha16(PAGE_SIZE)
190         add     r33, r33, r0
192         /* copy word at r10 to word at r11 until r11 equals r33 */
194         /* We know page size must be multiple of 16, so we can unroll
195          * 16 times safely without any edge case checking.
196          *
197          * Issue a flush of the destination every 16 words to avoid
198          * incoherence when starting the new kernel.  (Now this is
199          * just good paranoia because the hv_reexec call will also
200          * take care of this.)
201          */
204         { lw    r0, r10; addi   r10, r10, 4 }
205         { sw    r11, r0; addi   r11, r11, 4 }
206         { lw    r0, r10; addi   r10, r10, 4 }
207         { sw    r11, r0; addi   r11, r11, 4 }
208         { lw    r0, r10; addi   r10, r10, 4 }
209         { sw    r11, r0; addi   r11, r11, 4 }
210         { lw    r0, r10; addi   r10, r10, 4 }
211         { sw    r11, r0; addi   r11, r11, 4 }
212         { lw    r0, r10; addi   r10, r10, 4 }
213         { sw    r11, r0; addi   r11, r11, 4 }
214         { lw    r0, r10; addi   r10, r10, 4 }
215         { sw    r11, r0; addi   r11, r11, 4 }
216         { lw    r0, r10; addi   r10, r10, 4 }
217         { sw    r11, r0; addi   r11, r11, 4 }
218         { lw    r0, r10; addi   r10, r10, 4 }
219         { sw    r11, r0; addi   r11, r11, 4 }
220         { lw    r0, r10; addi   r10, r10, 4 }
221         { sw    r11, r0; addi   r11, r11, 4 }
222         { lw    r0, r10; addi   r10, r10, 4 }
223         { sw    r11, r0; addi   r11, r11, 4 }
224         { lw    r0, r10; addi   r10, r10, 4 }
225         { sw    r11, r0; addi   r11, r11, 4 }
226         { lw    r0, r10; addi   r10, r10, 4 }
227         { sw    r11, r0; addi   r11, r11, 4 }
228         { lw    r0, r10; addi   r10, r10, 4 }
229         { sw    r11, r0; addi   r11, r11, 4 }
230         { lw    r0, r10; addi   r10, r10, 4 }
231         { sw    r11, r0; addi   r11, r11, 4 }
232         { lw    r0, r10; addi   r10, r10, 4 }
233         { sw    r11, r0; addi   r11, r11, 4 }
234         { lw    r0, r10; addi   r10, r10, 4 }
235         { sw    r11, r0 }
236         { flush r11    ; addi   r11, r11, 4 }
238         seq     r0, r33, r11
239         bzt     r0, 1b
241 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
242         moveli  r0, 's'
243         jalr    r40
244 #endif
246         addi    r30, r30, 4
247         j       .Lloop
250 .Lerr:  moveli  r0, 'e'
251         jalr    r40
252         moveli  r0, 'r'
253         jalr    r40
254         moveli  r0, 'r'
255         jalr    r40
256         moveli  r0, '\n'
257         jalr    r40
258 .Lhalt:
259         moveli  r41, lo16(hv_halt)
260         auli    r41, r41, ha16(hv_halt)
262         jalr    r41
263         STD_ENDPROC(relocate_new_kernel)
265         .section .rodata,"a"
267         .globl relocate_new_kernel_size
268 relocate_new_kernel_size:
269         .long .Lend_relocate_new_kernel - relocate_new_kernel