• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/powerpc/kernel/
1/*
2 * This file contains miscellaneous low-level functions.
3 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
4 *
5 * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
6 * and Paul Mackerras.
7 *
8 * kexec bits:
9 * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
10 * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
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/sys.h>
20#include <asm/unistd.h>
21#include <asm/errno.h>
22#include <asm/reg.h>
23#include <asm/page.h>
24#include <asm/cache.h>
25#include <asm/cputable.h>
26#include <asm/mmu.h>
27#include <asm/ppc_asm.h>
28#include <asm/thread_info.h>
29#include <asm/asm-offsets.h>
30#include <asm/processor.h>
31#include <asm/kexec.h>
32#include <asm/bug.h>
33
34	.text
35
36_GLOBAL(call_do_softirq)
37	mflr	r0
38	stw	r0,4(r1)
39	stwu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
40	mr	r1,r3
41	bl	__do_softirq
42	lwz	r1,0(r1)
43	lwz	r0,4(r1)
44	mtlr	r0
45	blr
46
47_GLOBAL(call_handle_irq)
48	mflr	r0
49	stw	r0,4(r1)
50	mtctr	r6
51	stwu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
52	mr	r1,r5
53	bctrl
54	lwz	r1,0(r1)
55	lwz	r0,4(r1)
56	mtlr	r0
57	blr
58
59/*
60 * This returns the high 64 bits of the product of two 64-bit numbers.
61 */
62_GLOBAL(mulhdu)
63	cmpwi	r6,0
64	cmpwi	cr1,r3,0
65	mr	r10,r4
66	mulhwu	r4,r4,r5
67	beq	1f
68	mulhwu	r0,r10,r6
69	mullw	r7,r10,r5
70	addc	r7,r0,r7
71	addze	r4,r4
721:	beqlr	cr1		/* all done if high part of A is 0 */
73	mr	r10,r3
74	mullw	r9,r3,r5
75	mulhwu	r3,r3,r5
76	beq	2f
77	mullw	r0,r10,r6
78	mulhwu	r8,r10,r6
79	addc	r7,r0,r7
80	adde	r4,r4,r8
81	addze	r3,r3
822:	addc	r4,r4,r9
83	addze	r3,r3
84	blr
85
86/*
87 * sub_reloc_offset(x) returns x - reloc_offset().
88 */
89_GLOBAL(sub_reloc_offset)
90	mflr	r0
91	bl	1f
921:	mflr	r5
93	lis	r4,1b@ha
94	addi	r4,r4,1b@l
95	subf	r5,r4,r5
96	subf	r3,r5,r3
97	mtlr	r0
98	blr
99
100/*
101 * reloc_got2 runs through the .got2 section adding an offset
102 * to each entry.
103 */
104_GLOBAL(reloc_got2)
105	mflr	r11
106	lis	r7,__got2_start@ha
107	addi	r7,r7,__got2_start@l
108	lis	r8,__got2_end@ha
109	addi	r8,r8,__got2_end@l
110	subf	r8,r7,r8
111	srwi.	r8,r8,2
112	beqlr
113	mtctr	r8
114	bl	1f
1151:	mflr	r0
116	lis	r4,1b@ha
117	addi	r4,r4,1b@l
118	subf	r0,r4,r0
119	add	r7,r0,r7
1202:	lwz	r0,0(r7)
121	add	r0,r0,r3
122	stw	r0,0(r7)
123	addi	r7,r7,4
124	bdnz	2b
125	mtlr	r11
126	blr
127
128/*
129 * call_setup_cpu - call the setup_cpu function for this cpu
130 * r3 = data offset, r24 = cpu number
131 *
132 * Setup function is called with:
133 *   r3 = data offset
134 *   r4 = ptr to CPU spec (relocated)
135 */
136_GLOBAL(call_setup_cpu)
137	addis	r4,r3,cur_cpu_spec@ha
138	addi	r4,r4,cur_cpu_spec@l
139	lwz	r4,0(r4)
140	add	r4,r4,r3
141	lwz	r5,CPU_SPEC_SETUP(r4)
142	cmpwi	0,r5,0
143	add	r5,r5,r3
144	beqlr
145	mtctr	r5
146	bctr
147
148#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx)
149
150/* This gets called by via-pmu.c to switch the PLL selection
151 * on 750fx CPU. This function should really be moved to some
152 * other place (as most of the cpufreq code in via-pmu
153 */
154_GLOBAL(low_choose_750fx_pll)
155	/* Clear MSR:EE */
156	mfmsr	r7
157	rlwinm	r0,r7,0,17,15
158	mtmsr	r0
159
160	/* If switching to PLL1, disable HID0:BTIC */
161	cmplwi	cr0,r3,0
162	beq	1f
163	mfspr	r5,SPRN_HID0
164	rlwinm	r5,r5,0,27,25
165	sync
166	mtspr	SPRN_HID0,r5
167	isync
168	sync
169
1701:
171	/* Calc new HID1 value */
172	mfspr	r4,SPRN_HID1	/* Build a HID1:PS bit from parameter */
173	rlwinm	r5,r3,16,15,15	/* Clear out HID1:PS from value read */
174	rlwinm	r4,r4,0,16,14	/* Could have I used rlwimi here ? */
175	or	r4,r4,r5
176	mtspr	SPRN_HID1,r4
177
178	/* Store new HID1 image */
179	rlwinm	r6,r1,0,0,(31-THREAD_SHIFT)
180	lwz	r6,TI_CPU(r6)
181	slwi	r6,r6,2
182	addis	r6,r6,nap_save_hid1@ha
183	stw	r4,nap_save_hid1@l(r6)
184
185	/* If switching to PLL0, enable HID0:BTIC */
186	cmplwi	cr0,r3,0
187	bne	1f
188	mfspr	r5,SPRN_HID0
189	ori	r5,r5,HID0_BTIC
190	sync
191	mtspr	SPRN_HID0,r5
192	isync
193	sync
194
1951:
196	/* Return */
197	mtmsr	r7
198	blr
199
200_GLOBAL(low_choose_7447a_dfs)
201	/* Clear MSR:EE */
202	mfmsr	r7
203	rlwinm	r0,r7,0,17,15
204	mtmsr	r0
205
206	/* Calc new HID1 value */
207	mfspr	r4,SPRN_HID1
208	insrwi	r4,r3,1,9	/* insert parameter into bit 9 */
209	sync
210	mtspr	SPRN_HID1,r4
211	sync
212	isync
213
214	/* Return */
215	mtmsr	r7
216	blr
217
218#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */
219
220/*
221 * complement mask on the msr then "or" some values on.
222 *     _nmask_and_or_msr(nmask, value_to_or)
223 */
224_GLOBAL(_nmask_and_or_msr)
225	mfmsr	r0		/* Get current msr */
226	andc	r0,r0,r3	/* And off the bits set in r3 (first parm) */
227	or	r0,r0,r4	/* Or on the bits in r4 (second parm) */
228	SYNC			/* Some chip revs have problems here... */
229	mtmsr	r0		/* Update machine state */
230	isync
231	blr			/* Done */
232
233#ifdef CONFIG_40x
234
235/*
236 * Do an IO access in real mode
237 */
238_GLOBAL(real_readb)
239	mfmsr	r7
240	ori	r0,r7,MSR_DR
241	xori	r0,r0,MSR_DR
242	sync
243	mtmsr	r0
244	sync
245	isync
246	lbz	r3,0(r3)
247	sync
248	mtmsr	r7
249	sync
250	isync
251	blr
252
253	/*
254 * Do an IO access in real mode
255 */
256_GLOBAL(real_writeb)
257	mfmsr	r7
258	ori	r0,r7,MSR_DR
259	xori	r0,r0,MSR_DR
260	sync
261	mtmsr	r0
262	sync
263	isync
264	stb	r3,0(r4)
265	sync
266	mtmsr	r7
267	sync
268	isync
269	blr
270
271#endif /* CONFIG_40x */
272
273
274/*
275 * Flush instruction cache.
276 * This is a no-op on the 601.
277 */
278_GLOBAL(flush_instruction_cache)
279#if defined(CONFIG_8xx)
280	isync
281	lis	r5, IDC_INVALL@h
282	mtspr	SPRN_IC_CST, r5
283#elif defined(CONFIG_4xx)
284#ifdef CONFIG_403GCX
285	li      r3, 512
286	mtctr   r3
287	lis     r4, KERNELBASE@h
2881:	iccci   0, r4
289	addi    r4, r4, 16
290	bdnz    1b
291#else
292	lis	r3, KERNELBASE@h
293	iccci	0,r3
294#endif
295#elif CONFIG_FSL_BOOKE
296BEGIN_FTR_SECTION
297	mfspr   r3,SPRN_L1CSR0
298	ori     r3,r3,L1CSR0_CFI|L1CSR0_CLFC
299	/* msync; isync recommended here */
300	mtspr   SPRN_L1CSR0,r3
301	isync
302	blr
303END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
304	mfspr	r3,SPRN_L1CSR1
305	ori	r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
306	mtspr	SPRN_L1CSR1,r3
307#else
308	mfspr	r3,SPRN_PVR
309	rlwinm	r3,r3,16,16,31
310	cmpwi	0,r3,1
311	beqlr			/* for 601, do nothing */
312	/* 603/604 processor - use invalidate-all bit in HID0 */
313	mfspr	r3,SPRN_HID0
314	ori	r3,r3,HID0_ICFI
315	mtspr	SPRN_HID0,r3
316#endif /* CONFIG_8xx/4xx */
317	isync
318	blr
319
320/*
321 * Write any modified data cache blocks out to memory
322 * and invalidate the corresponding instruction cache blocks.
323 * This is a no-op on the 601.
324 *
325 * flush_icache_range(unsigned long start, unsigned long stop)
326 */
327_KPROBE(__flush_icache_range)
328BEGIN_FTR_SECTION
329	blr				/* for 601, do nothing */
330END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
331	li	r5,L1_CACHE_BYTES-1
332	andc	r3,r3,r5
333	subf	r4,r3,r4
334	add	r4,r4,r5
335	srwi.	r4,r4,L1_CACHE_SHIFT
336	beqlr
337	mtctr	r4
338	mr	r6,r3
3391:	dcbst	0,r3
340	addi	r3,r3,L1_CACHE_BYTES
341	bdnz	1b
342	sync				/* wait for dcbst's to get to ram */
343#ifndef CONFIG_44x
344	mtctr	r4
3452:	icbi	0,r6
346	addi	r6,r6,L1_CACHE_BYTES
347	bdnz	2b
348#else
349	/* Flash invalidate on 44x because we are passed kmapped addresses and
350	   this doesn't work for userspace pages due to the virtually tagged
351	   icache.  Sigh. */
352	iccci	0, r0
353#endif
354	sync				/* additional sync needed on g4 */
355	isync
356	blr
357/*
358 * Write any modified data cache blocks out to memory.
359 * Does not invalidate the corresponding cache lines (especially for
360 * any corresponding instruction cache).
361 *
362 * clean_dcache_range(unsigned long start, unsigned long stop)
363 */
364_GLOBAL(clean_dcache_range)
365	li	r5,L1_CACHE_BYTES-1
366	andc	r3,r3,r5
367	subf	r4,r3,r4
368	add	r4,r4,r5
369	srwi.	r4,r4,L1_CACHE_SHIFT
370	beqlr
371	mtctr	r4
372
3731:	dcbst	0,r3
374	addi	r3,r3,L1_CACHE_BYTES
375	bdnz	1b
376	sync				/* wait for dcbst's to get to ram */
377	blr
378
379/*
380 * Write any modified data cache blocks out to memory and invalidate them.
381 * Does not invalidate the corresponding instruction cache blocks.
382 *
383 * flush_dcache_range(unsigned long start, unsigned long stop)
384 */
385_GLOBAL(flush_dcache_range)
386	li	r5,L1_CACHE_BYTES-1
387	andc	r3,r3,r5
388	subf	r4,r3,r4
389	add	r4,r4,r5
390	srwi.	r4,r4,L1_CACHE_SHIFT
391	beqlr
392	mtctr	r4
393
3941:	dcbf	0,r3
395	addi	r3,r3,L1_CACHE_BYTES
396	bdnz	1b
397	sync				/* wait for dcbst's to get to ram */
398	blr
399
400/*
401 * Like above, but invalidate the D-cache.  This is used by the 8xx
402 * to invalidate the cache so the PPC core doesn't get stale data
403 * from the CPM (no cache snooping here :-).
404 *
405 * invalidate_dcache_range(unsigned long start, unsigned long stop)
406 */
407_GLOBAL(invalidate_dcache_range)
408	li	r5,L1_CACHE_BYTES-1
409	andc	r3,r3,r5
410	subf	r4,r3,r4
411	add	r4,r4,r5
412	srwi.	r4,r4,L1_CACHE_SHIFT
413	beqlr
414	mtctr	r4
415
4161:	dcbi	0,r3
417	addi	r3,r3,L1_CACHE_BYTES
418	bdnz	1b
419	sync				/* wait for dcbi's to get to ram */
420	blr
421
422/*
423 * Flush a particular page from the data cache to RAM.
424 * Note: this is necessary because the instruction cache does *not*
425 * snoop from the data cache.
426 * This is a no-op on the 601 which has a unified cache.
427 *
428 *	void __flush_dcache_icache(void *page)
429 */
430_GLOBAL(__flush_dcache_icache)
431BEGIN_FTR_SECTION
432	blr
433END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
434	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
435	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
436	mtctr	r4
437	mr	r6,r3
4380:	dcbst	0,r3				/* Write line to ram */
439	addi	r3,r3,L1_CACHE_BYTES
440	bdnz	0b
441	sync
442#ifdef CONFIG_44x
443	/* We don't flush the icache on 44x. Those have a virtual icache
444	 * and we don't have access to the virtual address here (it's
445	 * not the page vaddr but where it's mapped in user space). The
446	 * flushing of the icache on these is handled elsewhere, when
447	 * a change in the address space occurs, before returning to
448	 * user space
449	 */
450BEGIN_MMU_FTR_SECTION
451	blr
452END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
453#endif /* CONFIG_44x */
454	mtctr	r4
4551:	icbi	0,r6
456	addi	r6,r6,L1_CACHE_BYTES
457	bdnz	1b
458	sync
459	isync
460	blr
461
462#ifndef CONFIG_BOOKE
463/*
464 * Flush a particular page from the data cache to RAM, identified
465 * by its physical address.  We turn off the MMU so we can just use
466 * the physical address (this may be a highmem page without a kernel
467 * mapping).
468 *
469 *	void __flush_dcache_icache_phys(unsigned long physaddr)
470 */
471_GLOBAL(__flush_dcache_icache_phys)
472BEGIN_FTR_SECTION
473	blr					/* for 601, do nothing */
474END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
475	mfmsr	r10
476	rlwinm	r0,r10,0,28,26			/* clear DR */
477	mtmsr	r0
478	isync
479	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
480	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
481	mtctr	r4
482	mr	r6,r3
4830:	dcbst	0,r3				/* Write line to ram */
484	addi	r3,r3,L1_CACHE_BYTES
485	bdnz	0b
486	sync
487	mtctr	r4
4881:	icbi	0,r6
489	addi	r6,r6,L1_CACHE_BYTES
490	bdnz	1b
491	sync
492	mtmsr	r10				/* restore DR */
493	isync
494	blr
495#endif /* CONFIG_BOOKE */
496
497/*
498 * Clear pages using the dcbz instruction, which doesn't cause any
499 * memory traffic (except to write out any cache lines which get
500 * displaced).  This only works on cacheable memory.
501 *
502 * void clear_pages(void *page, int order) ;
503 */
504_GLOBAL(clear_pages)
505	li	r0,PAGE_SIZE/L1_CACHE_BYTES
506	slw	r0,r0,r4
507	mtctr	r0
5081:	dcbz	0,r3
509	addi	r3,r3,L1_CACHE_BYTES
510	bdnz	1b
511	blr
512
513/*
514 * Copy a whole page.  We use the dcbz instruction on the destination
515 * to reduce memory traffic (it eliminates the unnecessary reads of
516 * the destination into cache).  This requires that the destination
517 * is cacheable.
518 */
519#define COPY_16_BYTES		\
520	lwz	r6,4(r4);	\
521	lwz	r7,8(r4);	\
522	lwz	r8,12(r4);	\
523	lwzu	r9,16(r4);	\
524	stw	r6,4(r3);	\
525	stw	r7,8(r3);	\
526	stw	r8,12(r3);	\
527	stwu	r9,16(r3)
528
529_GLOBAL(copy_page)
530	addi	r3,r3,-4
531	addi	r4,r4,-4
532
533	li	r5,4
534
535#if MAX_COPY_PREFETCH > 1
536	li	r0,MAX_COPY_PREFETCH
537	li	r11,4
538	mtctr	r0
53911:	dcbt	r11,r4
540	addi	r11,r11,L1_CACHE_BYTES
541	bdnz	11b
542#else /* MAX_COPY_PREFETCH == 1 */
543	dcbt	r5,r4
544	li	r11,L1_CACHE_BYTES+4
545#endif /* MAX_COPY_PREFETCH */
546	li	r0,PAGE_SIZE/L1_CACHE_BYTES - MAX_COPY_PREFETCH
547	crclr	4*cr0+eq
5482:
549	mtctr	r0
5501:
551	dcbt	r11,r4
552	dcbz	r5,r3
553	COPY_16_BYTES
554#if L1_CACHE_BYTES >= 32
555	COPY_16_BYTES
556#if L1_CACHE_BYTES >= 64
557	COPY_16_BYTES
558	COPY_16_BYTES
559#if L1_CACHE_BYTES >= 128
560	COPY_16_BYTES
561	COPY_16_BYTES
562	COPY_16_BYTES
563	COPY_16_BYTES
564#endif
565#endif
566#endif
567	bdnz	1b
568	beqlr
569	crnot	4*cr0+eq,4*cr0+eq
570	li	r0,MAX_COPY_PREFETCH
571	li	r11,4
572	b	2b
573
574/*
575 * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
576 * void atomic_set_mask(atomic_t mask, atomic_t *addr);
577 */
578_GLOBAL(atomic_clear_mask)
57910:	lwarx	r5,0,r4
580	andc	r5,r5,r3
581	PPC405_ERR77(0,r4)
582	stwcx.	r5,0,r4
583	bne-	10b
584	blr
585_GLOBAL(atomic_set_mask)
58610:	lwarx	r5,0,r4
587	or	r5,r5,r3
588	PPC405_ERR77(0,r4)
589	stwcx.	r5,0,r4
590	bne-	10b
591	blr
592
593/*
594 * Extended precision shifts.
595 *
596 * Updated to be valid for shift counts from 0 to 63 inclusive.
597 * -- Gabriel
598 *
599 * R3/R4 has 64 bit value
600 * R5    has shift count
601 * result in R3/R4
602 *
603 *  ashrdi3: arithmetic right shift (sign propagation)
604 *  lshrdi3: logical right shift
605 *  ashldi3: left shift
606 */
607_GLOBAL(__ashrdi3)
608	subfic	r6,r5,32
609	srw	r4,r4,r5	# LSW = count > 31 ? 0 : LSW >> count
610	addi	r7,r5,32	# could be xori, or addi with -32
611	slw	r6,r3,r6	# t1 = count > 31 ? 0 : MSW << (32-count)
612	rlwinm	r8,r7,0,32	# t3 = (count < 32) ? 32 : 0
613	sraw	r7,r3,r7	# t2 = MSW >> (count-32)
614	or	r4,r4,r6	# LSW |= t1
615	slw	r7,r7,r8	# t2 = (count < 32) ? 0 : t2
616	sraw	r3,r3,r5	# MSW = MSW >> count
617	or	r4,r4,r7	# LSW |= t2
618	blr
619
620_GLOBAL(__ashldi3)
621	subfic	r6,r5,32
622	slw	r3,r3,r5	# MSW = count > 31 ? 0 : MSW << count
623	addi	r7,r5,32	# could be xori, or addi with -32
624	srw	r6,r4,r6	# t1 = count > 31 ? 0 : LSW >> (32-count)
625	slw	r7,r4,r7	# t2 = count < 32 ? 0 : LSW << (count-32)
626	or	r3,r3,r6	# MSW |= t1
627	slw	r4,r4,r5	# LSW = LSW << count
628	or	r3,r3,r7	# MSW |= t2
629	blr
630
631_GLOBAL(__lshrdi3)
632	subfic	r6,r5,32
633	srw	r4,r4,r5	# LSW = count > 31 ? 0 : LSW >> count
634	addi	r7,r5,32	# could be xori, or addi with -32
635	slw	r6,r3,r6	# t1 = count > 31 ? 0 : MSW << (32-count)
636	srw	r7,r3,r7	# t2 = count < 32 ? 0 : MSW >> (count-32)
637	or	r4,r4,r6	# LSW |= t1
638	srw	r3,r3,r5	# MSW = MSW >> count
639	or	r4,r4,r7	# LSW |= t2
640	blr
641
642/*
643 * 64-bit comparison: __ucmpdi2(u64 a, u64 b)
644 * Returns 0 if a < b, 1 if a == b, 2 if a > b.
645 */
646_GLOBAL(__ucmpdi2)
647	cmplw	r3,r5
648	li	r3,1
649	bne	1f
650	cmplw	r4,r6
651	beqlr
6521:	li	r3,0
653	bltlr
654	li	r3,2
655	blr
656
657_GLOBAL(abs)
658	srawi	r4,r3,31
659	xor	r3,r3,r4
660	sub	r3,r3,r4
661	blr
662
663/*
664 * Create a kernel thread
665 *   kernel_thread(fn, arg, flags)
666 */
667_GLOBAL(kernel_thread)
668	stwu	r1,-16(r1)
669	stw	r30,8(r1)
670	stw	r31,12(r1)
671	mr	r30,r3		/* function */
672	mr	r31,r4		/* argument */
673	ori	r3,r5,CLONE_VM	/* flags */
674	oris	r3,r3,CLONE_UNTRACED>>16
675	li	r4,0		/* new sp (unused) */
676	li	r0,__NR_clone
677	sc
678	bns+	1f		/* did system call indicate error? */
679	neg	r3,r3		/* if so, make return code negative */
6801:	cmpwi	0,r3,0		/* parent or child? */
681	bne	2f		/* return if parent */
682	li	r0,0		/* make top-level stack frame */
683	stwu	r0,-16(r1)
684	mtlr	r30		/* fn addr in lr */
685	mr	r3,r31		/* load arg and call fn */
686	PPC440EP_ERR42
687	blrl
688	li	r0,__NR_exit	/* exit if function returns */
689	li	r3,0
690	sc
6912:	lwz	r30,8(r1)
692	lwz	r31,12(r1)
693	addi	r1,r1,16
694	blr
695
696/*
697 * This routine is just here to keep GCC happy - sigh...
698 */
699_GLOBAL(__main)
700	blr
701
702#ifdef CONFIG_KEXEC
703	/*
704	 * Must be relocatable PIC code callable as a C function.
705	 */
706	.globl relocate_new_kernel
707relocate_new_kernel:
708	/* r3 = page_list   */
709	/* r4 = reboot_code_buffer */
710	/* r5 = start_address      */
711
712#ifdef CONFIG_FSL_BOOKE
713
714	mr	r29, r3
715	mr	r30, r4
716	mr	r31, r5
717
718#define ENTRY_MAPPING_KEXEC_SETUP
719#include "fsl_booke_entry_mapping.S"
720#undef ENTRY_MAPPING_KEXEC_SETUP
721
722	mr      r3, r29
723	mr      r4, r30
724	mr      r5, r31
725
726	li	r0, 0
727#else
728	li	r0, 0
729
730	/*
731	 * Set Machine Status Register to a known status,
732	 * switch the MMU off and jump to 1: in a single step.
733	 */
734
735	mr	r8, r0
736	ori     r8, r8, MSR_RI|MSR_ME
737	mtspr	SPRN_SRR1, r8
738	addi	r8, r4, 1f - relocate_new_kernel
739	mtspr	SPRN_SRR0, r8
740	sync
741	rfi
742
7431:
744#endif
745	/* from this point address translation is turned off */
746	/* and interrupts are disabled */
747
748	/* set a new stack at the bottom of our page... */
749	/* (not really needed now) */
750	addi	r1, r4, KEXEC_CONTROL_PAGE_SIZE - 8 /* for LR Save+Back Chain */
751	stw	r0, 0(r1)
752
753	/* Do the copies */
754	li	r6, 0 /* checksum */
755	mr	r0, r3
756	b	1f
757
7580:	/* top, read another word for the indirection page */
759	lwzu	r0, 4(r3)
760
7611:
762	/* is it a destination page? (r8) */
763	rlwinm.	r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
764	beq	2f
765
766	rlwinm	r8, r0, 0, 0, 19 /* clear kexec flags, page align */
767	b	0b
768
7692:	/* is it an indirection page? (r3) */
770	rlwinm.	r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
771	beq	2f
772
773	rlwinm	r3, r0, 0, 0, 19 /* clear kexec flags, page align */
774	subi	r3, r3, 4
775	b	0b
776
7772:	/* are we done? */
778	rlwinm.	r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
779	beq	2f
780	b	3f
781
7822:	/* is it a source page? (r9) */
783	rlwinm.	r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
784	beq	0b
785
786	rlwinm	r9, r0, 0, 0, 19 /* clear kexec flags, page align */
787
788	li	r7, PAGE_SIZE / 4
789	mtctr   r7
790	subi    r9, r9, 4
791	subi    r8, r8, 4
7929:
793	lwzu    r0, 4(r9)  /* do the copy */
794	xor	r6, r6, r0
795	stwu    r0, 4(r8)
796	dcbst	0, r8
797	sync
798	icbi	0, r8
799	bdnz    9b
800
801	addi    r9, r9, 4
802	addi    r8, r8, 4
803	b	0b
804
8053:
806
807	/* To be certain of avoiding problems with self-modifying code
808	 * execute a serializing instruction here.
809	 */
810	isync
811	sync
812
813	mfspr	r3, SPRN_PIR /* current core we are running on */
814	mr	r4, r5 /* load physical address of chunk called */
815
816	/* jump to the entry point, usually the setup routine */
817	mtlr	r5
818	blrl
819
8201:	b	1b
821
822relocate_new_kernel_end:
823
824	.globl relocate_new_kernel_size
825relocate_new_kernel_size:
826	.long relocate_new_kernel_end - relocate_new_kernel
827#endif
828