• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/tile/kernel/
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
34STD_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
2141:
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
279relocate_new_kernel_size:
280	.long .Lend_relocate_new_kernel - relocate_new_kernel
281