xref: /openbmc/linux/arch/powerpc/kernel/misc_64.S (revision da6658859b9c734fee36570f3a7d51764c6c3838)
19994a338SPaul Mackerras/*
29994a338SPaul Mackerras * This file contains miscellaneous low-level functions.
39994a338SPaul Mackerras *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
49994a338SPaul Mackerras *
59994a338SPaul Mackerras * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
69994a338SPaul Mackerras * and Paul Mackerras.
79994a338SPaul Mackerras * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
89994a338SPaul Mackerras * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
99994a338SPaul Mackerras *
109994a338SPaul Mackerras * This program is free software; you can redistribute it and/or
119994a338SPaul Mackerras * modify it under the terms of the GNU General Public License
129994a338SPaul Mackerras * as published by the Free Software Foundation; either version
139994a338SPaul Mackerras * 2 of the License, or (at your option) any later version.
149994a338SPaul Mackerras *
159994a338SPaul Mackerras */
169994a338SPaul Mackerras
179994a338SPaul Mackerras#include <linux/sys.h>
189994a338SPaul Mackerras#include <asm/unistd.h>
199994a338SPaul Mackerras#include <asm/errno.h>
209994a338SPaul Mackerras#include <asm/processor.h>
219994a338SPaul Mackerras#include <asm/page.h>
229994a338SPaul Mackerras#include <asm/cache.h>
239994a338SPaul Mackerras#include <asm/ppc_asm.h>
249994a338SPaul Mackerras#include <asm/asm-offsets.h>
259994a338SPaul Mackerras#include <asm/cputable.h>
266cb7bfebSDavid Gibson#include <asm/thread_info.h>
271fc711f7SMichael Neuling#include <asm/kexec.h>
2846f52210SStephen Rothwell#include <asm/ptrace.h>
29cf904e30STiejun Chen#include <asm/mmu.h>
309445aa1aSAl Viro#include <asm/export.h>
319994a338SPaul Mackerras
329994a338SPaul Mackerras	.text
339994a338SPaul Mackerras
349994a338SPaul Mackerras_GLOBAL(call_do_softirq)
359994a338SPaul Mackerras	mflr	r0
369994a338SPaul Mackerras	std	r0,16(r1)
374ae2dcb6SKumar Gala	stdu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
389994a338SPaul Mackerras	mr	r1,r3
39b1576fecSAnton Blanchard	bl	__do_softirq
409994a338SPaul Mackerras	ld	r1,0(r1)
419994a338SPaul Mackerras	ld	r0,16(r1)
429994a338SPaul Mackerras	mtlr	r0
439994a338SPaul Mackerras	blr
449994a338SPaul Mackerras
450366a1c7SBenjamin Herrenschmidt_GLOBAL(call_do_irq)
469994a338SPaul Mackerras	mflr	r0
479994a338SPaul Mackerras	std	r0,16(r1)
480366a1c7SBenjamin Herrenschmidt	stdu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
490366a1c7SBenjamin Herrenschmidt	mr	r1,r4
50b1576fecSAnton Blanchard	bl	__do_irq
519994a338SPaul Mackerras	ld	r1,0(r1)
529994a338SPaul Mackerras	ld	r0,16(r1)
539994a338SPaul Mackerras	mtlr	r0
549994a338SPaul Mackerras	blr
559994a338SPaul Mackerras
569994a338SPaul Mackerras	.section	".toc","aw"
579994a338SPaul MackerrasPPC64_CACHES:
589994a338SPaul Mackerras	.tc		ppc64_caches[TC],ppc64_caches
599994a338SPaul Mackerras	.section	".text"
609994a338SPaul Mackerras
619994a338SPaul Mackerras/*
629994a338SPaul Mackerras * Write any modified data cache blocks out to memory
639994a338SPaul Mackerras * and invalidate the corresponding instruction cache blocks.
649994a338SPaul Mackerras *
659994a338SPaul Mackerras * flush_icache_range(unsigned long start, unsigned long stop)
669994a338SPaul Mackerras *
679994a338SPaul Mackerras *   flush all bytes from start through stop-1 inclusive
689994a338SPaul Mackerras */
699994a338SPaul Mackerras
706f698df1SNicholas Piggin_GLOBAL(flush_icache_range)
71abb29c3bSKevin HaoBEGIN_FTR_SECTION
720ce63670SKevin Hao	PURGE_PREFETCHED_INS
73abb29c3bSKevin Hao	blr
74abb29c3bSKevin HaoEND_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
759994a338SPaul Mackerras/*
769994a338SPaul Mackerras * Flush the data cache to memory
779994a338SPaul Mackerras *
789994a338SPaul Mackerras * Different systems have different cache line sizes
799994a338SPaul Mackerras * and in some cases i-cache and d-cache line sizes differ from
809994a338SPaul Mackerras * each other.
819994a338SPaul Mackerras */
829994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
839994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)/* Get cache line size */
849994a338SPaul Mackerras	addi	r5,r7,-1
859994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
869994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
879994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
889994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
899994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
909994a338SPaul Mackerras	beqlr				/* nothing to do? */
919994a338SPaul Mackerras	mtctr	r8
929994a338SPaul Mackerras1:	dcbst	0,r6
939994a338SPaul Mackerras	add	r6,r6,r7
949994a338SPaul Mackerras	bdnz	1b
959994a338SPaul Mackerras	sync
969994a338SPaul Mackerras
979994a338SPaul Mackerras/* Now invalidate the instruction cache */
989994a338SPaul Mackerras
999994a338SPaul Mackerras	lwz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
1009994a338SPaul Mackerras	addi	r5,r7,-1
1019994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1029994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1039994a338SPaul Mackerras	add	r8,r8,r5
1049994a338SPaul Mackerras	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
1059994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1069994a338SPaul Mackerras	beqlr				/* nothing to do? */
1079994a338SPaul Mackerras	mtctr	r8
1089994a338SPaul Mackerras2:	icbi	0,r6
1099994a338SPaul Mackerras	add	r6,r6,r7
1109994a338SPaul Mackerras	bdnz	2b
1119994a338SPaul Mackerras	isync
1129994a338SPaul Mackerras	blr
1136f698df1SNicholas Piggin_ASM_NOKPROBE_SYMBOL(flush_icache_range)
1149445aa1aSAl ViroEXPORT_SYMBOL(flush_icache_range)
1156f698df1SNicholas Piggin
1169994a338SPaul Mackerras/*
1179994a338SPaul Mackerras * Like above, but only do the D-cache.
1189994a338SPaul Mackerras *
1199994a338SPaul Mackerras * flush_dcache_range(unsigned long start, unsigned long stop)
1209994a338SPaul Mackerras *
1219994a338SPaul Mackerras *    flush all bytes from start to stop-1 inclusive
1229994a338SPaul Mackerras */
1239994a338SPaul Mackerras_GLOBAL(flush_dcache_range)
1249994a338SPaul Mackerras
1259994a338SPaul Mackerras/*
1269994a338SPaul Mackerras * Flush the data cache to memory
1279994a338SPaul Mackerras *
1289994a338SPaul Mackerras * Different systems have different cache line sizes
1299994a338SPaul Mackerras */
1309994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
1319994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
1329994a338SPaul Mackerras	addi	r5,r7,-1
1339994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1349994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1359994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
1369994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
1379994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1389994a338SPaul Mackerras	beqlr				/* nothing to do? */
1399994a338SPaul Mackerras	mtctr	r8
1409994a338SPaul Mackerras0:	dcbst	0,r6
1419994a338SPaul Mackerras	add	r6,r6,r7
1429994a338SPaul Mackerras	bdnz	0b
1439994a338SPaul Mackerras	sync
1449994a338SPaul Mackerras	blr
1459445aa1aSAl ViroEXPORT_SYMBOL(flush_dcache_range)
1469994a338SPaul Mackerras
1479994a338SPaul Mackerras/*
1489994a338SPaul Mackerras * Like above, but works on non-mapped physical addresses.
1499994a338SPaul Mackerras * Use only for non-LPAR setups ! It also assumes real mode
1509994a338SPaul Mackerras * is cacheable. Used for flushing out the DART before using
1519994a338SPaul Mackerras * it as uncacheable memory
1529994a338SPaul Mackerras *
1539994a338SPaul Mackerras * flush_dcache_phys_range(unsigned long start, unsigned long stop)
1549994a338SPaul Mackerras *
1559994a338SPaul Mackerras *    flush all bytes from start to stop-1 inclusive
1569994a338SPaul Mackerras */
1579994a338SPaul Mackerras_GLOBAL(flush_dcache_phys_range)
1589994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
1599994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
1609994a338SPaul Mackerras	addi	r5,r7,-1
1619994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1629994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1639994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
1649994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
1659994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1669994a338SPaul Mackerras	beqlr				/* nothing to do? */
1679994a338SPaul Mackerras	mfmsr	r5			/* Disable MMU Data Relocation */
1689994a338SPaul Mackerras	ori	r0,r5,MSR_DR
1699994a338SPaul Mackerras	xori	r0,r0,MSR_DR
1709994a338SPaul Mackerras	sync
1719994a338SPaul Mackerras	mtmsr	r0
1729994a338SPaul Mackerras	sync
1739994a338SPaul Mackerras	isync
1749994a338SPaul Mackerras	mtctr	r8
1759994a338SPaul Mackerras0:	dcbst	0,r6
1769994a338SPaul Mackerras	add	r6,r6,r7
1779994a338SPaul Mackerras	bdnz	0b
1789994a338SPaul Mackerras	sync
1799994a338SPaul Mackerras	isync
1809994a338SPaul Mackerras	mtmsr	r5			/* Re-enable MMU Data Relocation */
1819994a338SPaul Mackerras	sync
1829994a338SPaul Mackerras	isync
1839994a338SPaul Mackerras	blr
1849994a338SPaul Mackerras
1859994a338SPaul Mackerras_GLOBAL(flush_inval_dcache_range)
1869994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
1879994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
1889994a338SPaul Mackerras	addi	r5,r7,-1
1899994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1909994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1919994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
1929994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
1939994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1949994a338SPaul Mackerras	beqlr				/* nothing to do? */
1959994a338SPaul Mackerras	sync
1969994a338SPaul Mackerras	isync
1979994a338SPaul Mackerras	mtctr	r8
1989994a338SPaul Mackerras0:	dcbf	0,r6
1999994a338SPaul Mackerras	add	r6,r6,r7
2009994a338SPaul Mackerras	bdnz	0b
2019994a338SPaul Mackerras	sync
2029994a338SPaul Mackerras	isync
2039994a338SPaul Mackerras	blr
2049994a338SPaul Mackerras
2059994a338SPaul Mackerras
2069994a338SPaul Mackerras/*
2079994a338SPaul Mackerras * Flush a particular page from the data cache to RAM.
2089994a338SPaul Mackerras * Note: this is necessary because the instruction cache does *not*
2099994a338SPaul Mackerras * snoop from the data cache.
2109994a338SPaul Mackerras *
2119994a338SPaul Mackerras *	void __flush_dcache_icache(void *page)
2129994a338SPaul Mackerras */
2139994a338SPaul Mackerras_GLOBAL(__flush_dcache_icache)
2149994a338SPaul Mackerras/*
2159994a338SPaul Mackerras * Flush the data cache to memory
2169994a338SPaul Mackerras *
2179994a338SPaul Mackerras * Different systems have different cache line sizes
2189994a338SPaul Mackerras */
2199994a338SPaul Mackerras
2200ce63670SKevin HaoBEGIN_FTR_SECTION
2210ce63670SKevin Hao	PURGE_PREFETCHED_INS
2220ce63670SKevin Hao	blr
2230ce63670SKevin HaoEND_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
2240ce63670SKevin Hao
2259994a338SPaul Mackerras/* Flush the dcache */
2269994a338SPaul Mackerras 	ld	r7,PPC64_CACHES@toc(r2)
2279994a338SPaul Mackerras	clrrdi	r3,r3,PAGE_SHIFT           	    /* Page align */
2289994a338SPaul Mackerras	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
2299994a338SPaul Mackerras	lwz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
2309994a338SPaul Mackerras	mr	r6,r3
2319994a338SPaul Mackerras	mtctr	r4
2329994a338SPaul Mackerras0:	dcbst	0,r6
2339994a338SPaul Mackerras	add	r6,r6,r5
2349994a338SPaul Mackerras	bdnz	0b
2359994a338SPaul Mackerras	sync
2369994a338SPaul Mackerras
2379994a338SPaul Mackerras/* Now invalidate the icache */
2389994a338SPaul Mackerras
2399994a338SPaul Mackerras	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
2409994a338SPaul Mackerras	lwz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
2419994a338SPaul Mackerras	mtctr	r4
2429994a338SPaul Mackerras1:	icbi	0,r3
2439994a338SPaul Mackerras	add	r3,r3,r5
2449994a338SPaul Mackerras	bdnz	1b
2459994a338SPaul Mackerras	isync
2469994a338SPaul Mackerras	blr
2479994a338SPaul Mackerras
248ca9d7aeaSDavid Woodhouse_GLOBAL(__bswapdi2)
2499445aa1aSAl ViroEXPORT_SYMBOL(__bswapdi2)
250ca9d7aeaSDavid Woodhouse	srdi	r8,r3,32
251ca9d7aeaSDavid Woodhouse	rlwinm	r7,r3,8,0xffffffff
252ca9d7aeaSDavid Woodhouse	rlwimi	r7,r3,24,0,7
253ca9d7aeaSDavid Woodhouse	rlwinm	r9,r8,8,0xffffffff
254ca9d7aeaSDavid Woodhouse	rlwimi	r7,r3,24,16,23
255ca9d7aeaSDavid Woodhouse	rlwimi	r9,r8,24,0,7
256ca9d7aeaSDavid Woodhouse	rlwimi	r9,r8,24,16,23
257ca9d7aeaSDavid Woodhouse	sldi	r7,r7,32
258ca9d7aeaSDavid Woodhouse	or	r3,r7,r9
259ca9d7aeaSDavid Woodhouse	blr
2603f639ee8SStephen Rothwell
2617191b615SBenjamin Herrenschmidt
2622d6f0c3aSMichael Ellerman#ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX
2637191b615SBenjamin Herrenschmidt_GLOBAL(rmci_on)
2647191b615SBenjamin Herrenschmidt	sync
2657191b615SBenjamin Herrenschmidt	isync
2667191b615SBenjamin Herrenschmidt	li	r3,0x100
2677191b615SBenjamin Herrenschmidt	rldicl	r3,r3,32,0
2687191b615SBenjamin Herrenschmidt	mfspr	r5,SPRN_HID4
2697191b615SBenjamin Herrenschmidt	or	r5,r5,r3
2707191b615SBenjamin Herrenschmidt	sync
2717191b615SBenjamin Herrenschmidt	mtspr	SPRN_HID4,r5
2727191b615SBenjamin Herrenschmidt	isync
2737191b615SBenjamin Herrenschmidt	slbia
2747191b615SBenjamin Herrenschmidt	isync
2757191b615SBenjamin Herrenschmidt	sync
2767191b615SBenjamin Herrenschmidt	blr
2777191b615SBenjamin Herrenschmidt
2787191b615SBenjamin Herrenschmidt_GLOBAL(rmci_off)
2797191b615SBenjamin Herrenschmidt	sync
2807191b615SBenjamin Herrenschmidt	isync
2817191b615SBenjamin Herrenschmidt	li	r3,0x100
2827191b615SBenjamin Herrenschmidt	rldicl	r3,r3,32,0
2837191b615SBenjamin Herrenschmidt	mfspr	r5,SPRN_HID4
2847191b615SBenjamin Herrenschmidt	andc	r5,r5,r3
2857191b615SBenjamin Herrenschmidt	sync
2867191b615SBenjamin Herrenschmidt	mtspr	SPRN_HID4,r5
2877191b615SBenjamin Herrenschmidt	isync
2887191b615SBenjamin Herrenschmidt	slbia
2897191b615SBenjamin Herrenschmidt	isync
2907191b615SBenjamin Herrenschmidt	sync
2917191b615SBenjamin Herrenschmidt	blr
2922d6f0c3aSMichael Ellerman#endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */
2932d6f0c3aSMichael Ellerman
2942d6f0c3aSMichael Ellerman#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
2957191b615SBenjamin Herrenschmidt
2969994a338SPaul Mackerras/*
2979994a338SPaul Mackerras * Do an IO access in real mode
2989994a338SPaul Mackerras */
2999994a338SPaul Mackerras_GLOBAL(real_readb)
3009994a338SPaul Mackerras	mfmsr	r7
3019994a338SPaul Mackerras	ori	r0,r7,MSR_DR
3029994a338SPaul Mackerras	xori	r0,r0,MSR_DR
3039994a338SPaul Mackerras	sync
3049994a338SPaul Mackerras	mtmsrd	r0
3059994a338SPaul Mackerras	sync
3069994a338SPaul Mackerras	isync
3079994a338SPaul Mackerras	mfspr	r6,SPRN_HID4
3089994a338SPaul Mackerras	rldicl	r5,r6,32,0
3099994a338SPaul Mackerras	ori	r5,r5,0x100
3109994a338SPaul Mackerras	rldicl	r5,r5,32,0
3119994a338SPaul Mackerras	sync
3129994a338SPaul Mackerras	mtspr	SPRN_HID4,r5
3139994a338SPaul Mackerras	isync
3149994a338SPaul Mackerras	slbia
3159994a338SPaul Mackerras	isync
3169994a338SPaul Mackerras	lbz	r3,0(r3)
3179994a338SPaul Mackerras	sync
3189994a338SPaul Mackerras	mtspr	SPRN_HID4,r6
3199994a338SPaul Mackerras	isync
3209994a338SPaul Mackerras	slbia
3219994a338SPaul Mackerras	isync
3229994a338SPaul Mackerras	mtmsrd	r7
3239994a338SPaul Mackerras	sync
3249994a338SPaul Mackerras	isync
3259994a338SPaul Mackerras	blr
3269994a338SPaul Mackerras
3279994a338SPaul Mackerras	/*
3289994a338SPaul Mackerras * Do an IO access in real mode
3299994a338SPaul Mackerras */
3309994a338SPaul Mackerras_GLOBAL(real_writeb)
3319994a338SPaul Mackerras	mfmsr	r7
3329994a338SPaul Mackerras	ori	r0,r7,MSR_DR
3339994a338SPaul Mackerras	xori	r0,r0,MSR_DR
3349994a338SPaul Mackerras	sync
3359994a338SPaul Mackerras	mtmsrd	r0
3369994a338SPaul Mackerras	sync
3379994a338SPaul Mackerras	isync
3389994a338SPaul Mackerras	mfspr	r6,SPRN_HID4
3399994a338SPaul Mackerras	rldicl	r5,r6,32,0
3409994a338SPaul Mackerras	ori	r5,r5,0x100
3419994a338SPaul Mackerras	rldicl	r5,r5,32,0
3429994a338SPaul Mackerras	sync
3439994a338SPaul Mackerras	mtspr	SPRN_HID4,r5
3449994a338SPaul Mackerras	isync
3459994a338SPaul Mackerras	slbia
3469994a338SPaul Mackerras	isync
3479994a338SPaul Mackerras	stb	r3,0(r4)
3489994a338SPaul Mackerras	sync
3499994a338SPaul Mackerras	mtspr	SPRN_HID4,r6
3509994a338SPaul Mackerras	isync
3519994a338SPaul Mackerras	slbia
3529994a338SPaul Mackerras	isync
3539994a338SPaul Mackerras	mtmsrd	r7
3549994a338SPaul Mackerras	sync
3559994a338SPaul Mackerras	isync
3569994a338SPaul Mackerras	blr
3579994a338SPaul Mackerras#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
3589994a338SPaul Mackerras
35939c870d5SOlof Johansson#ifdef CONFIG_PPC_PASEMI
36039c870d5SOlof Johansson
36139c870d5SOlof Johansson_GLOBAL(real_205_readb)
36239c870d5SOlof Johansson	mfmsr	r7
36339c870d5SOlof Johansson	ori	r0,r7,MSR_DR
36439c870d5SOlof Johansson	xori	r0,r0,MSR_DR
36539c870d5SOlof Johansson	sync
36639c870d5SOlof Johansson	mtmsrd	r0
36739c870d5SOlof Johansson	sync
36839c870d5SOlof Johansson	isync
369e55174e9SMichael Neuling	LBZCIX(R3,R0,R3)
37039c870d5SOlof Johansson	isync
37139c870d5SOlof Johansson	mtmsrd	r7
37239c870d5SOlof Johansson	sync
37339c870d5SOlof Johansson	isync
37439c870d5SOlof Johansson	blr
37539c870d5SOlof Johansson
37639c870d5SOlof Johansson_GLOBAL(real_205_writeb)
37739c870d5SOlof Johansson	mfmsr	r7
37839c870d5SOlof Johansson	ori	r0,r7,MSR_DR
37939c870d5SOlof Johansson	xori	r0,r0,MSR_DR
38039c870d5SOlof Johansson	sync
38139c870d5SOlof Johansson	mtmsrd	r0
38239c870d5SOlof Johansson	sync
38339c870d5SOlof Johansson	isync
384e55174e9SMichael Neuling	STBCIX(R3,R0,R4)
38539c870d5SOlof Johansson	isync
38639c870d5SOlof Johansson	mtmsrd	r7
38739c870d5SOlof Johansson	sync
38839c870d5SOlof Johansson	isync
38939c870d5SOlof Johansson	blr
39039c870d5SOlof Johansson
39139c870d5SOlof Johansson#endif /* CONFIG_PPC_PASEMI */
39239c870d5SOlof Johansson
39339c870d5SOlof Johansson
394e48f7eb2SDmitry Eremin-Solenikov#if defined(CONFIG_CPU_FREQ_PMAC64) || defined(CONFIG_CPU_FREQ_MAPLE)
3959994a338SPaul Mackerras/*
3964350147aSBenjamin Herrenschmidt * SCOM access functions for 970 (FX only for now)
3974350147aSBenjamin Herrenschmidt *
3984350147aSBenjamin Herrenschmidt * unsigned long scom970_read(unsigned int address);
3994350147aSBenjamin Herrenschmidt * void scom970_write(unsigned int address, unsigned long value);
4004350147aSBenjamin Herrenschmidt *
4014350147aSBenjamin Herrenschmidt * The address passed in is the 24 bits register address. This code
4024350147aSBenjamin Herrenschmidt * is 970 specific and will not check the status bits, so you should
4034350147aSBenjamin Herrenschmidt * know what you are doing.
4044350147aSBenjamin Herrenschmidt */
4054350147aSBenjamin Herrenschmidt_GLOBAL(scom970_read)
4064350147aSBenjamin Herrenschmidt	/* interrupts off */
4074350147aSBenjamin Herrenschmidt	mfmsr	r4
4084350147aSBenjamin Herrenschmidt	ori	r0,r4,MSR_EE
4094350147aSBenjamin Herrenschmidt	xori	r0,r0,MSR_EE
4104350147aSBenjamin Herrenschmidt	mtmsrd	r0,1
4114350147aSBenjamin Herrenschmidt
4124350147aSBenjamin Herrenschmidt	/* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
4134350147aSBenjamin Herrenschmidt	 * (including parity). On current CPUs they must be 0'd,
4144350147aSBenjamin Herrenschmidt	 * and finally or in RW bit
4154350147aSBenjamin Herrenschmidt	 */
4164350147aSBenjamin Herrenschmidt	rlwinm	r3,r3,8,0,15
4174350147aSBenjamin Herrenschmidt	ori	r3,r3,0x8000
4184350147aSBenjamin Herrenschmidt
4194350147aSBenjamin Herrenschmidt	/* do the actual scom read */
4204350147aSBenjamin Herrenschmidt	sync
4214350147aSBenjamin Herrenschmidt	mtspr	SPRN_SCOMC,r3
4224350147aSBenjamin Herrenschmidt	isync
4234350147aSBenjamin Herrenschmidt	mfspr	r3,SPRN_SCOMD
4244350147aSBenjamin Herrenschmidt	isync
4254350147aSBenjamin Herrenschmidt	mfspr	r0,SPRN_SCOMC
4264350147aSBenjamin Herrenschmidt	isync
4274350147aSBenjamin Herrenschmidt
4284350147aSBenjamin Herrenschmidt	/* XXX:	fixup result on some buggy 970's (ouch ! we lost a bit, bah
4294350147aSBenjamin Herrenschmidt	 * that's the best we can do). Not implemented yet as we don't use
4304350147aSBenjamin Herrenschmidt	 * the scom on any of the bogus CPUs yet, but may have to be done
4314350147aSBenjamin Herrenschmidt	 * ultimately
4324350147aSBenjamin Herrenschmidt	 */
4334350147aSBenjamin Herrenschmidt
4344350147aSBenjamin Herrenschmidt	/* restore interrupts */
4354350147aSBenjamin Herrenschmidt	mtmsrd	r4,1
4364350147aSBenjamin Herrenschmidt	blr
4374350147aSBenjamin Herrenschmidt
4384350147aSBenjamin Herrenschmidt
4394350147aSBenjamin Herrenschmidt_GLOBAL(scom970_write)
4404350147aSBenjamin Herrenschmidt	/* interrupts off */
4414350147aSBenjamin Herrenschmidt	mfmsr	r5
4424350147aSBenjamin Herrenschmidt	ori	r0,r5,MSR_EE
4434350147aSBenjamin Herrenschmidt	xori	r0,r0,MSR_EE
4444350147aSBenjamin Herrenschmidt	mtmsrd	r0,1
4454350147aSBenjamin Herrenschmidt
4464350147aSBenjamin Herrenschmidt	/* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
4474350147aSBenjamin Herrenschmidt	 * (including parity). On current CPUs they must be 0'd.
4484350147aSBenjamin Herrenschmidt	 */
4494350147aSBenjamin Herrenschmidt
4504350147aSBenjamin Herrenschmidt	rlwinm	r3,r3,8,0,15
4514350147aSBenjamin Herrenschmidt
4524350147aSBenjamin Herrenschmidt	sync
4534350147aSBenjamin Herrenschmidt	mtspr	SPRN_SCOMD,r4      /* write data */
4544350147aSBenjamin Herrenschmidt	isync
4554350147aSBenjamin Herrenschmidt	mtspr	SPRN_SCOMC,r3      /* write command */
4564350147aSBenjamin Herrenschmidt	isync
4574350147aSBenjamin Herrenschmidt	mfspr	3,SPRN_SCOMC
4584350147aSBenjamin Herrenschmidt	isync
4594350147aSBenjamin Herrenschmidt
4604350147aSBenjamin Herrenschmidt	/* restore interrupts */
4614350147aSBenjamin Herrenschmidt	mtmsrd	r5,1
4624350147aSBenjamin Herrenschmidt	blr
463e48f7eb2SDmitry Eremin-Solenikov#endif /* CONFIG_CPU_FREQ_PMAC64 || CONFIG_CPU_FREQ_MAPLE */
4644350147aSBenjamin Herrenschmidt
4659994a338SPaul Mackerras/* kexec_wait(phys_cpu)
4669994a338SPaul Mackerras *
4679994a338SPaul Mackerras * wait for the flag to change, indicating this kernel is going away but
4689994a338SPaul Mackerras * the slave code for the next one is at addresses 0 to 100.
4699994a338SPaul Mackerras *
4703d2cea73SMilton Miller * This is used by all slaves, even those that did not find a matching
4713d2cea73SMilton Miller * paca in the secondary startup code.
4729994a338SPaul Mackerras *
4739994a338SPaul Mackerras * Physical (hardware) cpu id should be in r3.
4749994a338SPaul Mackerras */
4759994a338SPaul Mackerras_GLOBAL(kexec_wait)
4769994a338SPaul Mackerras	bl	1f
4779994a338SPaul Mackerras1:	mflr	r5
4789994a338SPaul Mackerras	addi	r5,r5,kexec_flag-1b
4799994a338SPaul Mackerras
4809994a338SPaul Mackerras99:	HMT_LOW
481*da665885SThiago Jung Bauermann#ifdef CONFIG_KEXEC_CORE	/* use no memory without kexec */
4829994a338SPaul Mackerras	lwz	r4,0(r5)
4839994a338SPaul Mackerras	cmpwi	0,r4,0
484ffebf5f3SSamuel Mendoza-Jonas	beq	99b
485ffebf5f3SSamuel Mendoza-Jonas#ifdef CONFIG_PPC_BOOK3S_64
486ffebf5f3SSamuel Mendoza-Jonas	li	r10,0x60
487ffebf5f3SSamuel Mendoza-Jonas	mfmsr	r11
488ffebf5f3SSamuel Mendoza-Jonas	clrrdi	r11,r11,1	/* Clear MSR_LE */
489ffebf5f3SSamuel Mendoza-Jonas	mtsrr0	r10
490ffebf5f3SSamuel Mendoza-Jonas	mtsrr1	r11
491ffebf5f3SSamuel Mendoza-Jonas	rfid
492ffebf5f3SSamuel Mendoza-Jonas#else
493ae73e4ccSScott Wood	/* Create TLB entry in book3e_secondary_core_init */
494ae73e4ccSScott Wood	li	r4,0
495ffebf5f3SSamuel Mendoza-Jonas	ba	0x60
4969994a338SPaul Mackerras#endif
497ffebf5f3SSamuel Mendoza-Jonas#endif
4989994a338SPaul Mackerras
4999994a338SPaul Mackerras/* this can be in text because we won't change it until we are
5009994a338SPaul Mackerras * running in real anyways
5019994a338SPaul Mackerras */
5029994a338SPaul Mackerraskexec_flag:
5039994a338SPaul Mackerras	.long	0
5049994a338SPaul Mackerras
5059994a338SPaul Mackerras
506*da665885SThiago Jung Bauermann#ifdef CONFIG_KEXEC_CORE
507cf904e30STiejun Chen#ifdef CONFIG_PPC_BOOK3E
508cf904e30STiejun Chen/*
509cf904e30STiejun Chen * BOOK3E has no real MMU mode, so we have to setup the initial TLB
510cf904e30STiejun Chen * for a core to identity map v:0 to p:0.  This current implementation
511cf904e30STiejun Chen * assumes that 1G is enough for kexec.
512cf904e30STiejun Chen */
513cf904e30STiejun Chenkexec_create_tlb:
514cf904e30STiejun Chen	/*
515cf904e30STiejun Chen	 * Invalidate all non-IPROT TLB entries to avoid any TLB conflict.
516cf904e30STiejun Chen	 * IPROT TLB entries should be >= PAGE_OFFSET and thus not conflict.
517cf904e30STiejun Chen	 */
518cf904e30STiejun Chen	PPC_TLBILX_ALL(0,R0)
519cf904e30STiejun Chen	sync
520cf904e30STiejun Chen	isync
521cf904e30STiejun Chen
522cf904e30STiejun Chen	mfspr	r10,SPRN_TLB1CFG
523cf904e30STiejun Chen	andi.	r10,r10,TLBnCFG_N_ENTRY	/* Extract # entries */
524cf904e30STiejun Chen	subi	r10,r10,1	/* Last entry: no conflict with kernel text */
525cf904e30STiejun Chen	lis	r9,MAS0_TLBSEL(1)@h
526cf904e30STiejun Chen	rlwimi	r9,r10,16,4,15		/* Setup MAS0 = TLBSEL | ESEL(r9) */
527cf904e30STiejun Chen
528cf904e30STiejun Chen/* Set up a temp identity mapping v:0 to p:0 and return to it. */
529cf904e30STiejun Chen#if defined(CONFIG_SMP) || defined(CONFIG_PPC_E500MC)
530cf904e30STiejun Chen#define M_IF_NEEDED	MAS2_M
531cf904e30STiejun Chen#else
532cf904e30STiejun Chen#define M_IF_NEEDED	0
533cf904e30STiejun Chen#endif
534cf904e30STiejun Chen	mtspr	SPRN_MAS0,r9
535cf904e30STiejun Chen
536cf904e30STiejun Chen	lis	r9,(MAS1_VALID|MAS1_IPROT)@h
537cf904e30STiejun Chen	ori	r9,r9,(MAS1_TSIZE(BOOK3E_PAGESZ_1GB))@l
538cf904e30STiejun Chen	mtspr	SPRN_MAS1,r9
539cf904e30STiejun Chen
540cf904e30STiejun Chen	LOAD_REG_IMMEDIATE(r9, 0x0 | M_IF_NEEDED)
541cf904e30STiejun Chen	mtspr	SPRN_MAS2,r9
542cf904e30STiejun Chen
543cf904e30STiejun Chen	LOAD_REG_IMMEDIATE(r9, 0x0 | MAS3_SR | MAS3_SW | MAS3_SX)
544cf904e30STiejun Chen	mtspr	SPRN_MAS3,r9
545cf904e30STiejun Chen	li	r9,0
546cf904e30STiejun Chen	mtspr	SPRN_MAS7,r9
547cf904e30STiejun Chen
548cf904e30STiejun Chen	tlbwe
549cf904e30STiejun Chen	isync
550cf904e30STiejun Chen	blr
551cf904e30STiejun Chen#endif
5529994a338SPaul Mackerras
5539994a338SPaul Mackerras/* kexec_smp_wait(void)
5549994a338SPaul Mackerras *
5559994a338SPaul Mackerras * call with interrupts off
5569994a338SPaul Mackerras * note: this is a terminal routine, it does not save lr
5579994a338SPaul Mackerras *
5589994a338SPaul Mackerras * get phys id from paca
5599994a338SPaul Mackerras * switch to real mode
5603d2cea73SMilton Miller * mark the paca as no longer used
5619994a338SPaul Mackerras * join other cpus in kexec_wait(phys_id)
5629994a338SPaul Mackerras */
5639994a338SPaul Mackerras_GLOBAL(kexec_smp_wait)
5649994a338SPaul Mackerras	lhz	r3,PACAHWCPUID(r13)
5659994a338SPaul Mackerras	bl	real_mode
5663d2cea73SMilton Miller
5673d2cea73SMilton Miller	li	r4,KEXEC_STATE_REAL_MODE
5683d2cea73SMilton Miller	stb	r4,PACAKEXECSTATE(r13)
5693d2cea73SMilton Miller	SYNC
5703d2cea73SMilton Miller
571b1576fecSAnton Blanchard	b	kexec_wait
5729994a338SPaul Mackerras
5739994a338SPaul Mackerras/*
5749994a338SPaul Mackerras * switch to real mode (turn mmu off)
5759994a338SPaul Mackerras * we use the early kernel trick that the hardware ignores bits
5769994a338SPaul Mackerras * 0 and 1 (big endian) of the effective address in real mode
5779994a338SPaul Mackerras *
5789994a338SPaul Mackerras * don't overwrite r3 here, it is live for kexec_wait above.
5799994a338SPaul Mackerras */
5809994a338SPaul Mackerrasreal_mode:	/* assume normal blr return */
581cf904e30STiejun Chen#ifdef CONFIG_PPC_BOOK3E
582cf904e30STiejun Chen	/* Create an identity mapping. */
583cf904e30STiejun Chen	b	kexec_create_tlb
584cf904e30STiejun Chen#else
5859994a338SPaul Mackerras1:	li	r9,MSR_RI
5869994a338SPaul Mackerras	li	r10,MSR_DR|MSR_IR
5879994a338SPaul Mackerras	mflr	r11		/* return address to SRR0 */
5889994a338SPaul Mackerras	mfmsr	r12
5899994a338SPaul Mackerras	andc	r9,r12,r9
5909994a338SPaul Mackerras	andc	r10,r12,r10
5919994a338SPaul Mackerras
5929994a338SPaul Mackerras	mtmsrd	r9,1
5939994a338SPaul Mackerras	mtspr	SPRN_SRR1,r10
5949994a338SPaul Mackerras	mtspr	SPRN_SRR0,r11
5959994a338SPaul Mackerras	rfid
596cf904e30STiejun Chen#endif
5979994a338SPaul Mackerras
5989994a338SPaul Mackerras/*
599b970b41eSBenjamin Herrenschmidt * kexec_sequence(newstack, start, image, control, clear_all(),
600b970b41eSBenjamin Herrenschmidt	          copy_with_mmu_off)
6019994a338SPaul Mackerras *
6029994a338SPaul Mackerras * does the grungy work with stack switching and real mode switches
6039994a338SPaul Mackerras * also does simple calls to other code
6049994a338SPaul Mackerras */
6059994a338SPaul Mackerras
6069994a338SPaul Mackerras_GLOBAL(kexec_sequence)
6079994a338SPaul Mackerras	mflr	r0
6089994a338SPaul Mackerras	std	r0,16(r1)
6099994a338SPaul Mackerras
6109994a338SPaul Mackerras	/* switch stacks to newstack -- &kexec_stack.stack */
6114ae2dcb6SKumar Gala	stdu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
6129994a338SPaul Mackerras	mr	r1,r3
6139994a338SPaul Mackerras
6149994a338SPaul Mackerras	li	r0,0
6159994a338SPaul Mackerras	std	r0,16(r1)
6169994a338SPaul Mackerras
6179994a338SPaul Mackerras	/* save regs for local vars on new stack.
6189994a338SPaul Mackerras	 * yes, we won't go back, but ...
6199994a338SPaul Mackerras	 */
6209994a338SPaul Mackerras	std	r31,-8(r1)
6219994a338SPaul Mackerras	std	r30,-16(r1)
6229994a338SPaul Mackerras	std	r29,-24(r1)
6239994a338SPaul Mackerras	std	r28,-32(r1)
6249994a338SPaul Mackerras	std	r27,-40(r1)
6259994a338SPaul Mackerras	std	r26,-48(r1)
6269994a338SPaul Mackerras	std	r25,-56(r1)
6279994a338SPaul Mackerras
6284ae2dcb6SKumar Gala	stdu	r1,-STACK_FRAME_OVERHEAD-64(r1)
6299994a338SPaul Mackerras
6309994a338SPaul Mackerras	/* save args into preserved regs */
6319994a338SPaul Mackerras	mr	r31,r3			/* newstack (both) */
6329994a338SPaul Mackerras	mr	r30,r4			/* start (real) */
6339994a338SPaul Mackerras	mr	r29,r5			/* image (virt) */
6349994a338SPaul Mackerras	mr	r28,r6			/* control, unused */
6359994a338SPaul Mackerras	mr	r27,r7			/* clear_all() fn desc */
636b970b41eSBenjamin Herrenschmidt	mr	r26,r8			/* copy_with_mmu_off */
6379994a338SPaul Mackerras	lhz	r25,PACAHWCPUID(r13)	/* get our phys cpu from paca */
6389994a338SPaul Mackerras
6399994a338SPaul Mackerras	/* disable interrupts, we are overwriting kernel data next */
64096eea642STiejun Chen#ifdef CONFIG_PPC_BOOK3E
64196eea642STiejun Chen	wrteei	0
64296eea642STiejun Chen#else
6439994a338SPaul Mackerras	mfmsr	r3
6449994a338SPaul Mackerras	rlwinm	r3,r3,0,17,15
6459994a338SPaul Mackerras	mtmsrd	r3,1
64696eea642STiejun Chen#endif
6479994a338SPaul Mackerras
648b970b41eSBenjamin Herrenschmidt	/* We need to turn the MMU off unless we are in hash mode
649b970b41eSBenjamin Herrenschmidt	 * under a hypervisor
650b970b41eSBenjamin Herrenschmidt	 */
651b970b41eSBenjamin Herrenschmidt	cmpdi	r26,0
652b970b41eSBenjamin Herrenschmidt	beq	1f
653b970b41eSBenjamin Herrenschmidt	bl	real_mode
654b970b41eSBenjamin Herrenschmidt1:
6559994a338SPaul Mackerras	/* copy dest pages, flush whole dest image */
6569994a338SPaul Mackerras	mr	r3,r29
657b1576fecSAnton Blanchard	bl	kexec_copy_flush	/* (image) */
6589994a338SPaul Mackerras
659b970b41eSBenjamin Herrenschmidt	/* turn off mmu now if not done earlier */
660b970b41eSBenjamin Herrenschmidt	cmpdi	r26,0
661b970b41eSBenjamin Herrenschmidt	bne	1f
6629994a338SPaul Mackerras	bl	real_mode
6639994a338SPaul Mackerras
664ee46a90bSMilton Miller	/* copy  0x100 bytes starting at start to 0 */
665b970b41eSBenjamin Herrenschmidt1:	li	r3,0
666ee46a90bSMilton Miller	mr	r4,r30		/* start, aka phys mem offset */
667ee46a90bSMilton Miller	li	r5,0x100
668ee46a90bSMilton Miller	li	r6,0
669b1576fecSAnton Blanchard	bl	copy_and_flush	/* (dest, src, copy limit, start offset) */
670ee46a90bSMilton Miller1:	/* assume normal blr return */
671ee46a90bSMilton Miller
672ee46a90bSMilton Miller	/* release other cpus to the new kernel secondary start at 0x60 */
673ee46a90bSMilton Miller	mflr	r5
674ee46a90bSMilton Miller	li	r6,1
675ee46a90bSMilton Miller	stw	r6,kexec_flag-1b(5)
676ee46a90bSMilton Miller
677fc48bad5SBenjamin Herrenschmidt	cmpdi	r27,0
678fc48bad5SBenjamin Herrenschmidt	beq	1f
679fc48bad5SBenjamin Herrenschmidt
6809994a338SPaul Mackerras	/* clear out hardware hash page table and tlb */
681f55d9665SMichael Ellerman#ifdef PPC64_ELF_ABI_v1
682cc7efbf9SAnton Blanchard	ld	r12,0(r27)		/* deref function descriptor */
683cc7efbf9SAnton Blanchard#else
684cc7efbf9SAnton Blanchard	mr	r12,r27
685cc7efbf9SAnton Blanchard#endif
686cc7efbf9SAnton Blanchard	mtctr	r12
6877025776eSBenjamin Herrenschmidt	bctrl				/* mmu_hash_ops.hpte_clear_all(void); */
6889994a338SPaul Mackerras
6899994a338SPaul Mackerras/*
6909994a338SPaul Mackerras *   kexec image calling is:
6919994a338SPaul Mackerras *      the first 0x100 bytes of the entry point are copied to 0
6929994a338SPaul Mackerras *
6939994a338SPaul Mackerras *      all slaves branch to slave = 0x60 (absolute)
6949994a338SPaul Mackerras *              slave(phys_cpu_id);
6959994a338SPaul Mackerras *
6969994a338SPaul Mackerras *      master goes to start = entry point
6979994a338SPaul Mackerras *              start(phys_cpu_id, start, 0);
6989994a338SPaul Mackerras *
6999994a338SPaul Mackerras *
7009994a338SPaul Mackerras *   a wrapper is needed to call existing kernels, here is an approximate
7019994a338SPaul Mackerras *   description of one method:
7029994a338SPaul Mackerras *
7039994a338SPaul Mackerras * v2: (2.6.10)
7049994a338SPaul Mackerras *   start will be near the boot_block (maybe 0x100 bytes before it?)
7059994a338SPaul Mackerras *   it will have a 0x60, which will b to boot_block, where it will wait
7069994a338SPaul Mackerras *   and 0 will store phys into struct boot-block and load r3 from there,
7079994a338SPaul Mackerras *   copy kernel 0-0x100 and tell slaves to back down to 0x60 again
7089994a338SPaul Mackerras *
7099994a338SPaul Mackerras * v1: (2.6.9)
7109994a338SPaul Mackerras *    boot block will have all cpus scanning device tree to see if they
7119994a338SPaul Mackerras *    are the boot cpu ?????
7129994a338SPaul Mackerras *    other device tree differences (prop sizes, va vs pa, etc)...
7139994a338SPaul Mackerras */
714fc48bad5SBenjamin Herrenschmidt1:	mr	r3,r25	# my phys cpu
7159994a338SPaul Mackerras	mr	r4,r30	# start, aka phys mem offset
7169994a338SPaul Mackerras	mtlr	4
7179994a338SPaul Mackerras	li	r5,0
7181767c8f3SMilton Miller	blr	/* image->start(physid, image->start, 0); */
719*da665885SThiago Jung Bauermann#endif /* CONFIG_KEXEC_CORE */
720