xref: /openbmc/linux/arch/powerpc/kernel/misc_64.S (revision cc7efbf91933a4b59c20e60115c336b26dfc1195)
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>
299994a338SPaul Mackerras
309994a338SPaul Mackerras	.text
319994a338SPaul Mackerras
329994a338SPaul Mackerras_GLOBAL(call_do_softirq)
339994a338SPaul Mackerras	mflr	r0
349994a338SPaul Mackerras	std	r0,16(r1)
354ae2dcb6SKumar Gala	stdu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
369994a338SPaul Mackerras	mr	r1,r3
37b1576fecSAnton Blanchard	bl	__do_softirq
389994a338SPaul Mackerras	ld	r1,0(r1)
399994a338SPaul Mackerras	ld	r0,16(r1)
409994a338SPaul Mackerras	mtlr	r0
419994a338SPaul Mackerras	blr
429994a338SPaul Mackerras
430366a1c7SBenjamin Herrenschmidt_GLOBAL(call_do_irq)
449994a338SPaul Mackerras	mflr	r0
459994a338SPaul Mackerras	std	r0,16(r1)
460366a1c7SBenjamin Herrenschmidt	stdu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
470366a1c7SBenjamin Herrenschmidt	mr	r1,r4
48b1576fecSAnton Blanchard	bl	__do_irq
499994a338SPaul Mackerras	ld	r1,0(r1)
509994a338SPaul Mackerras	ld	r0,16(r1)
519994a338SPaul Mackerras	mtlr	r0
529994a338SPaul Mackerras	blr
539994a338SPaul Mackerras
549994a338SPaul Mackerras	.section	".toc","aw"
559994a338SPaul MackerrasPPC64_CACHES:
569994a338SPaul Mackerras	.tc		ppc64_caches[TC],ppc64_caches
579994a338SPaul Mackerras	.section	".text"
589994a338SPaul Mackerras
599994a338SPaul Mackerras/*
609994a338SPaul Mackerras * Write any modified data cache blocks out to memory
619994a338SPaul Mackerras * and invalidate the corresponding instruction cache blocks.
629994a338SPaul Mackerras *
639994a338SPaul Mackerras * flush_icache_range(unsigned long start, unsigned long stop)
649994a338SPaul Mackerras *
659994a338SPaul Mackerras *   flush all bytes from start through stop-1 inclusive
669994a338SPaul Mackerras */
679994a338SPaul Mackerras
683b04c300SKevin Hao_KPROBE(flush_icache_range)
69abb29c3bSKevin HaoBEGIN_FTR_SECTION
700ce63670SKevin Hao	PURGE_PREFETCHED_INS
71abb29c3bSKevin Hao	blr
72abb29c3bSKevin HaoEND_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
739994a338SPaul Mackerras/*
749994a338SPaul Mackerras * Flush the data cache to memory
759994a338SPaul Mackerras *
769994a338SPaul Mackerras * Different systems have different cache line sizes
779994a338SPaul Mackerras * and in some cases i-cache and d-cache line sizes differ from
789994a338SPaul Mackerras * each other.
799994a338SPaul Mackerras */
809994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
819994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)/* Get cache line size */
829994a338SPaul Mackerras	addi	r5,r7,-1
839994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
849994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
859994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
869994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
879994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
889994a338SPaul Mackerras	beqlr				/* nothing to do? */
899994a338SPaul Mackerras	mtctr	r8
909994a338SPaul Mackerras1:	dcbst	0,r6
919994a338SPaul Mackerras	add	r6,r6,r7
929994a338SPaul Mackerras	bdnz	1b
939994a338SPaul Mackerras	sync
949994a338SPaul Mackerras
959994a338SPaul Mackerras/* Now invalidate the instruction cache */
969994a338SPaul Mackerras
979994a338SPaul Mackerras	lwz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
989994a338SPaul Mackerras	addi	r5,r7,-1
999994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1009994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1019994a338SPaul Mackerras	add	r8,r8,r5
1029994a338SPaul Mackerras	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
1039994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1049994a338SPaul Mackerras	beqlr				/* nothing to do? */
1059994a338SPaul Mackerras	mtctr	r8
1069994a338SPaul Mackerras2:	icbi	0,r6
1079994a338SPaul Mackerras	add	r6,r6,r7
1089994a338SPaul Mackerras	bdnz	2b
1099994a338SPaul Mackerras	isync
1109994a338SPaul Mackerras	blr
1119994a338SPaul Mackerras	.previous .text
1129994a338SPaul Mackerras/*
1139994a338SPaul Mackerras * Like above, but only do the D-cache.
1149994a338SPaul Mackerras *
1159994a338SPaul Mackerras * flush_dcache_range(unsigned long start, unsigned long stop)
1169994a338SPaul Mackerras *
1179994a338SPaul Mackerras *    flush all bytes from start to stop-1 inclusive
1189994a338SPaul Mackerras */
1199994a338SPaul Mackerras_GLOBAL(flush_dcache_range)
1209994a338SPaul Mackerras
1219994a338SPaul Mackerras/*
1229994a338SPaul Mackerras * Flush the data cache to memory
1239994a338SPaul Mackerras *
1249994a338SPaul Mackerras * Different systems have different cache line sizes
1259994a338SPaul Mackerras */
1269994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
1279994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
1289994a338SPaul Mackerras	addi	r5,r7,-1
1299994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1309994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1319994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
1329994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
1339994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1349994a338SPaul Mackerras	beqlr				/* nothing to do? */
1359994a338SPaul Mackerras	mtctr	r8
1369994a338SPaul Mackerras0:	dcbst	0,r6
1379994a338SPaul Mackerras	add	r6,r6,r7
1389994a338SPaul Mackerras	bdnz	0b
1399994a338SPaul Mackerras	sync
1409994a338SPaul Mackerras	blr
1419994a338SPaul Mackerras
1429994a338SPaul Mackerras/*
1439994a338SPaul Mackerras * Like above, but works on non-mapped physical addresses.
1449994a338SPaul Mackerras * Use only for non-LPAR setups ! It also assumes real mode
1459994a338SPaul Mackerras * is cacheable. Used for flushing out the DART before using
1469994a338SPaul Mackerras * it as uncacheable memory
1479994a338SPaul Mackerras *
1489994a338SPaul Mackerras * flush_dcache_phys_range(unsigned long start, unsigned long stop)
1499994a338SPaul Mackerras *
1509994a338SPaul Mackerras *    flush all bytes from start to stop-1 inclusive
1519994a338SPaul Mackerras */
1529994a338SPaul Mackerras_GLOBAL(flush_dcache_phys_range)
1539994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
1549994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
1559994a338SPaul Mackerras	addi	r5,r7,-1
1569994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1579994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1589994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
1599994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
1609994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1619994a338SPaul Mackerras	beqlr				/* nothing to do? */
1629994a338SPaul Mackerras	mfmsr	r5			/* Disable MMU Data Relocation */
1639994a338SPaul Mackerras	ori	r0,r5,MSR_DR
1649994a338SPaul Mackerras	xori	r0,r0,MSR_DR
1659994a338SPaul Mackerras	sync
1669994a338SPaul Mackerras	mtmsr	r0
1679994a338SPaul Mackerras	sync
1689994a338SPaul Mackerras	isync
1699994a338SPaul Mackerras	mtctr	r8
1709994a338SPaul Mackerras0:	dcbst	0,r6
1719994a338SPaul Mackerras	add	r6,r6,r7
1729994a338SPaul Mackerras	bdnz	0b
1739994a338SPaul Mackerras	sync
1749994a338SPaul Mackerras	isync
1759994a338SPaul Mackerras	mtmsr	r5			/* Re-enable MMU Data Relocation */
1769994a338SPaul Mackerras	sync
1779994a338SPaul Mackerras	isync
1789994a338SPaul Mackerras	blr
1799994a338SPaul Mackerras
1809994a338SPaul Mackerras_GLOBAL(flush_inval_dcache_range)
1819994a338SPaul Mackerras 	ld	r10,PPC64_CACHES@toc(r2)
1829994a338SPaul Mackerras	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
1839994a338SPaul Mackerras	addi	r5,r7,-1
1849994a338SPaul Mackerras	andc	r6,r3,r5		/* round low to line bdy */
1859994a338SPaul Mackerras	subf	r8,r6,r4		/* compute length */
1869994a338SPaul Mackerras	add	r8,r8,r5		/* ensure we get enough */
1879994a338SPaul Mackerras	lwz	r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
1889994a338SPaul Mackerras	srw.	r8,r8,r9		/* compute line count */
1899994a338SPaul Mackerras	beqlr				/* nothing to do? */
1909994a338SPaul Mackerras	sync
1919994a338SPaul Mackerras	isync
1929994a338SPaul Mackerras	mtctr	r8
1939994a338SPaul Mackerras0:	dcbf	0,r6
1949994a338SPaul Mackerras	add	r6,r6,r7
1959994a338SPaul Mackerras	bdnz	0b
1969994a338SPaul Mackerras	sync
1979994a338SPaul Mackerras	isync
1989994a338SPaul Mackerras	blr
1999994a338SPaul Mackerras
2009994a338SPaul Mackerras
2019994a338SPaul Mackerras/*
2029994a338SPaul Mackerras * Flush a particular page from the data cache to RAM.
2039994a338SPaul Mackerras * Note: this is necessary because the instruction cache does *not*
2049994a338SPaul Mackerras * snoop from the data cache.
2059994a338SPaul Mackerras *
2069994a338SPaul Mackerras *	void __flush_dcache_icache(void *page)
2079994a338SPaul Mackerras */
2089994a338SPaul Mackerras_GLOBAL(__flush_dcache_icache)
2099994a338SPaul Mackerras/*
2109994a338SPaul Mackerras * Flush the data cache to memory
2119994a338SPaul Mackerras *
2129994a338SPaul Mackerras * Different systems have different cache line sizes
2139994a338SPaul Mackerras */
2149994a338SPaul Mackerras
2150ce63670SKevin HaoBEGIN_FTR_SECTION
2160ce63670SKevin Hao	PURGE_PREFETCHED_INS
2170ce63670SKevin Hao	blr
2180ce63670SKevin HaoEND_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
2190ce63670SKevin Hao
2209994a338SPaul Mackerras/* Flush the dcache */
2219994a338SPaul Mackerras 	ld	r7,PPC64_CACHES@toc(r2)
2229994a338SPaul Mackerras	clrrdi	r3,r3,PAGE_SHIFT           	    /* Page align */
2239994a338SPaul Mackerras	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
2249994a338SPaul Mackerras	lwz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
2259994a338SPaul Mackerras	mr	r6,r3
2269994a338SPaul Mackerras	mtctr	r4
2279994a338SPaul Mackerras0:	dcbst	0,r6
2289994a338SPaul Mackerras	add	r6,r6,r5
2299994a338SPaul Mackerras	bdnz	0b
2309994a338SPaul Mackerras	sync
2319994a338SPaul Mackerras
2329994a338SPaul Mackerras/* Now invalidate the icache */
2339994a338SPaul Mackerras
2349994a338SPaul Mackerras	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
2359994a338SPaul Mackerras	lwz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
2369994a338SPaul Mackerras	mtctr	r4
2379994a338SPaul Mackerras1:	icbi	0,r3
2389994a338SPaul Mackerras	add	r3,r3,r5
2399994a338SPaul Mackerras	bdnz	1b
2409994a338SPaul Mackerras	isync
2419994a338SPaul Mackerras	blr
2429994a338SPaul Mackerras
243ca9d7aeaSDavid Woodhouse_GLOBAL(__bswapdi2)
244ca9d7aeaSDavid Woodhouse	srdi	r8,r3,32
245ca9d7aeaSDavid Woodhouse	rlwinm	r7,r3,8,0xffffffff
246ca9d7aeaSDavid Woodhouse	rlwimi	r7,r3,24,0,7
247ca9d7aeaSDavid Woodhouse	rlwinm	r9,r8,8,0xffffffff
248ca9d7aeaSDavid Woodhouse	rlwimi	r7,r3,24,16,23
249ca9d7aeaSDavid Woodhouse	rlwimi	r9,r8,24,0,7
250ca9d7aeaSDavid Woodhouse	rlwimi	r9,r8,24,16,23
251ca9d7aeaSDavid Woodhouse	sldi	r7,r7,32
252ca9d7aeaSDavid Woodhouse	or	r3,r7,r9
253ca9d7aeaSDavid Woodhouse	blr
2543f639ee8SStephen Rothwell
2557191b615SBenjamin Herrenschmidt
2562d6f0c3aSMichael Ellerman#ifdef CONFIG_PPC_EARLY_DEBUG_BOOTX
2577191b615SBenjamin Herrenschmidt_GLOBAL(rmci_on)
2587191b615SBenjamin Herrenschmidt	sync
2597191b615SBenjamin Herrenschmidt	isync
2607191b615SBenjamin Herrenschmidt	li	r3,0x100
2617191b615SBenjamin Herrenschmidt	rldicl	r3,r3,32,0
2627191b615SBenjamin Herrenschmidt	mfspr	r5,SPRN_HID4
2637191b615SBenjamin Herrenschmidt	or	r5,r5,r3
2647191b615SBenjamin Herrenschmidt	sync
2657191b615SBenjamin Herrenschmidt	mtspr	SPRN_HID4,r5
2667191b615SBenjamin Herrenschmidt	isync
2677191b615SBenjamin Herrenschmidt	slbia
2687191b615SBenjamin Herrenschmidt	isync
2697191b615SBenjamin Herrenschmidt	sync
2707191b615SBenjamin Herrenschmidt	blr
2717191b615SBenjamin Herrenschmidt
2727191b615SBenjamin Herrenschmidt_GLOBAL(rmci_off)
2737191b615SBenjamin Herrenschmidt	sync
2747191b615SBenjamin Herrenschmidt	isync
2757191b615SBenjamin Herrenschmidt	li	r3,0x100
2767191b615SBenjamin Herrenschmidt	rldicl	r3,r3,32,0
2777191b615SBenjamin Herrenschmidt	mfspr	r5,SPRN_HID4
2787191b615SBenjamin Herrenschmidt	andc	r5,r5,r3
2797191b615SBenjamin Herrenschmidt	sync
2807191b615SBenjamin Herrenschmidt	mtspr	SPRN_HID4,r5
2817191b615SBenjamin Herrenschmidt	isync
2827191b615SBenjamin Herrenschmidt	slbia
2837191b615SBenjamin Herrenschmidt	isync
2847191b615SBenjamin Herrenschmidt	sync
2857191b615SBenjamin Herrenschmidt	blr
2862d6f0c3aSMichael Ellerman#endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */
2872d6f0c3aSMichael Ellerman
2882d6f0c3aSMichael Ellerman#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
2897191b615SBenjamin Herrenschmidt
2909994a338SPaul Mackerras/*
2919994a338SPaul Mackerras * Do an IO access in real mode
2929994a338SPaul Mackerras */
2939994a338SPaul Mackerras_GLOBAL(real_readb)
2949994a338SPaul Mackerras	mfmsr	r7
2959994a338SPaul Mackerras	ori	r0,r7,MSR_DR
2969994a338SPaul Mackerras	xori	r0,r0,MSR_DR
2979994a338SPaul Mackerras	sync
2989994a338SPaul Mackerras	mtmsrd	r0
2999994a338SPaul Mackerras	sync
3009994a338SPaul Mackerras	isync
3019994a338SPaul Mackerras	mfspr	r6,SPRN_HID4
3029994a338SPaul Mackerras	rldicl	r5,r6,32,0
3039994a338SPaul Mackerras	ori	r5,r5,0x100
3049994a338SPaul Mackerras	rldicl	r5,r5,32,0
3059994a338SPaul Mackerras	sync
3069994a338SPaul Mackerras	mtspr	SPRN_HID4,r5
3079994a338SPaul Mackerras	isync
3089994a338SPaul Mackerras	slbia
3099994a338SPaul Mackerras	isync
3109994a338SPaul Mackerras	lbz	r3,0(r3)
3119994a338SPaul Mackerras	sync
3129994a338SPaul Mackerras	mtspr	SPRN_HID4,r6
3139994a338SPaul Mackerras	isync
3149994a338SPaul Mackerras	slbia
3159994a338SPaul Mackerras	isync
3169994a338SPaul Mackerras	mtmsrd	r7
3179994a338SPaul Mackerras	sync
3189994a338SPaul Mackerras	isync
3199994a338SPaul Mackerras	blr
3209994a338SPaul Mackerras
3219994a338SPaul Mackerras	/*
3229994a338SPaul Mackerras * Do an IO access in real mode
3239994a338SPaul Mackerras */
3249994a338SPaul Mackerras_GLOBAL(real_writeb)
3259994a338SPaul Mackerras	mfmsr	r7
3269994a338SPaul Mackerras	ori	r0,r7,MSR_DR
3279994a338SPaul Mackerras	xori	r0,r0,MSR_DR
3289994a338SPaul Mackerras	sync
3299994a338SPaul Mackerras	mtmsrd	r0
3309994a338SPaul Mackerras	sync
3319994a338SPaul Mackerras	isync
3329994a338SPaul Mackerras	mfspr	r6,SPRN_HID4
3339994a338SPaul Mackerras	rldicl	r5,r6,32,0
3349994a338SPaul Mackerras	ori	r5,r5,0x100
3359994a338SPaul Mackerras	rldicl	r5,r5,32,0
3369994a338SPaul Mackerras	sync
3379994a338SPaul Mackerras	mtspr	SPRN_HID4,r5
3389994a338SPaul Mackerras	isync
3399994a338SPaul Mackerras	slbia
3409994a338SPaul Mackerras	isync
3419994a338SPaul Mackerras	stb	r3,0(r4)
3429994a338SPaul Mackerras	sync
3439994a338SPaul Mackerras	mtspr	SPRN_HID4,r6
3449994a338SPaul Mackerras	isync
3459994a338SPaul Mackerras	slbia
3469994a338SPaul Mackerras	isync
3479994a338SPaul Mackerras	mtmsrd	r7
3489994a338SPaul Mackerras	sync
3499994a338SPaul Mackerras	isync
3509994a338SPaul Mackerras	blr
3519994a338SPaul Mackerras#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
3529994a338SPaul Mackerras
35339c870d5SOlof Johansson#ifdef CONFIG_PPC_PASEMI
35439c870d5SOlof Johansson
35539c870d5SOlof Johansson_GLOBAL(real_205_readb)
35639c870d5SOlof Johansson	mfmsr	r7
35739c870d5SOlof Johansson	ori	r0,r7,MSR_DR
35839c870d5SOlof Johansson	xori	r0,r0,MSR_DR
35939c870d5SOlof Johansson	sync
36039c870d5SOlof Johansson	mtmsrd	r0
36139c870d5SOlof Johansson	sync
36239c870d5SOlof Johansson	isync
363e55174e9SMichael Neuling	LBZCIX(R3,R0,R3)
36439c870d5SOlof Johansson	isync
36539c870d5SOlof Johansson	mtmsrd	r7
36639c870d5SOlof Johansson	sync
36739c870d5SOlof Johansson	isync
36839c870d5SOlof Johansson	blr
36939c870d5SOlof Johansson
37039c870d5SOlof Johansson_GLOBAL(real_205_writeb)
37139c870d5SOlof Johansson	mfmsr	r7
37239c870d5SOlof Johansson	ori	r0,r7,MSR_DR
37339c870d5SOlof Johansson	xori	r0,r0,MSR_DR
37439c870d5SOlof Johansson	sync
37539c870d5SOlof Johansson	mtmsrd	r0
37639c870d5SOlof Johansson	sync
37739c870d5SOlof Johansson	isync
378e55174e9SMichael Neuling	STBCIX(R3,R0,R4)
37939c870d5SOlof Johansson	isync
38039c870d5SOlof Johansson	mtmsrd	r7
38139c870d5SOlof Johansson	sync
38239c870d5SOlof Johansson	isync
38339c870d5SOlof Johansson	blr
38439c870d5SOlof Johansson
38539c870d5SOlof Johansson#endif /* CONFIG_PPC_PASEMI */
38639c870d5SOlof Johansson
38739c870d5SOlof Johansson
388e48f7eb2SDmitry Eremin-Solenikov#if defined(CONFIG_CPU_FREQ_PMAC64) || defined(CONFIG_CPU_FREQ_MAPLE)
3899994a338SPaul Mackerras/*
3904350147aSBenjamin Herrenschmidt * SCOM access functions for 970 (FX only for now)
3914350147aSBenjamin Herrenschmidt *
3924350147aSBenjamin Herrenschmidt * unsigned long scom970_read(unsigned int address);
3934350147aSBenjamin Herrenschmidt * void scom970_write(unsigned int address, unsigned long value);
3944350147aSBenjamin Herrenschmidt *
3954350147aSBenjamin Herrenschmidt * The address passed in is the 24 bits register address. This code
3964350147aSBenjamin Herrenschmidt * is 970 specific and will not check the status bits, so you should
3974350147aSBenjamin Herrenschmidt * know what you are doing.
3984350147aSBenjamin Herrenschmidt */
3994350147aSBenjamin Herrenschmidt_GLOBAL(scom970_read)
4004350147aSBenjamin Herrenschmidt	/* interrupts off */
4014350147aSBenjamin Herrenschmidt	mfmsr	r4
4024350147aSBenjamin Herrenschmidt	ori	r0,r4,MSR_EE
4034350147aSBenjamin Herrenschmidt	xori	r0,r0,MSR_EE
4044350147aSBenjamin Herrenschmidt	mtmsrd	r0,1
4054350147aSBenjamin Herrenschmidt
4064350147aSBenjamin Herrenschmidt	/* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
4074350147aSBenjamin Herrenschmidt	 * (including parity). On current CPUs they must be 0'd,
4084350147aSBenjamin Herrenschmidt	 * and finally or in RW bit
4094350147aSBenjamin Herrenschmidt	 */
4104350147aSBenjamin Herrenschmidt	rlwinm	r3,r3,8,0,15
4114350147aSBenjamin Herrenschmidt	ori	r3,r3,0x8000
4124350147aSBenjamin Herrenschmidt
4134350147aSBenjamin Herrenschmidt	/* do the actual scom read */
4144350147aSBenjamin Herrenschmidt	sync
4154350147aSBenjamin Herrenschmidt	mtspr	SPRN_SCOMC,r3
4164350147aSBenjamin Herrenschmidt	isync
4174350147aSBenjamin Herrenschmidt	mfspr	r3,SPRN_SCOMD
4184350147aSBenjamin Herrenschmidt	isync
4194350147aSBenjamin Herrenschmidt	mfspr	r0,SPRN_SCOMC
4204350147aSBenjamin Herrenschmidt	isync
4214350147aSBenjamin Herrenschmidt
4224350147aSBenjamin Herrenschmidt	/* XXX:	fixup result on some buggy 970's (ouch ! we lost a bit, bah
4234350147aSBenjamin Herrenschmidt	 * that's the best we can do). Not implemented yet as we don't use
4244350147aSBenjamin Herrenschmidt	 * the scom on any of the bogus CPUs yet, but may have to be done
4254350147aSBenjamin Herrenschmidt	 * ultimately
4264350147aSBenjamin Herrenschmidt	 */
4274350147aSBenjamin Herrenschmidt
4284350147aSBenjamin Herrenschmidt	/* restore interrupts */
4294350147aSBenjamin Herrenschmidt	mtmsrd	r4,1
4304350147aSBenjamin Herrenschmidt	blr
4314350147aSBenjamin Herrenschmidt
4324350147aSBenjamin Herrenschmidt
4334350147aSBenjamin Herrenschmidt_GLOBAL(scom970_write)
4344350147aSBenjamin Herrenschmidt	/* interrupts off */
4354350147aSBenjamin Herrenschmidt	mfmsr	r5
4364350147aSBenjamin Herrenschmidt	ori	r0,r5,MSR_EE
4374350147aSBenjamin Herrenschmidt	xori	r0,r0,MSR_EE
4384350147aSBenjamin Herrenschmidt	mtmsrd	r0,1
4394350147aSBenjamin Herrenschmidt
4404350147aSBenjamin Herrenschmidt	/* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
4414350147aSBenjamin Herrenschmidt	 * (including parity). On current CPUs they must be 0'd.
4424350147aSBenjamin Herrenschmidt	 */
4434350147aSBenjamin Herrenschmidt
4444350147aSBenjamin Herrenschmidt	rlwinm	r3,r3,8,0,15
4454350147aSBenjamin Herrenschmidt
4464350147aSBenjamin Herrenschmidt	sync
4474350147aSBenjamin Herrenschmidt	mtspr	SPRN_SCOMD,r4      /* write data */
4484350147aSBenjamin Herrenschmidt	isync
4494350147aSBenjamin Herrenschmidt	mtspr	SPRN_SCOMC,r3      /* write command */
4504350147aSBenjamin Herrenschmidt	isync
4514350147aSBenjamin Herrenschmidt	mfspr	3,SPRN_SCOMC
4524350147aSBenjamin Herrenschmidt	isync
4534350147aSBenjamin Herrenschmidt
4544350147aSBenjamin Herrenschmidt	/* restore interrupts */
4554350147aSBenjamin Herrenschmidt	mtmsrd	r5,1
4564350147aSBenjamin Herrenschmidt	blr
457e48f7eb2SDmitry Eremin-Solenikov#endif /* CONFIG_CPU_FREQ_PMAC64 || CONFIG_CPU_FREQ_MAPLE */
4584350147aSBenjamin Herrenschmidt
4599994a338SPaul Mackerras/* kexec_wait(phys_cpu)
4609994a338SPaul Mackerras *
4619994a338SPaul Mackerras * wait for the flag to change, indicating this kernel is going away but
4629994a338SPaul Mackerras * the slave code for the next one is at addresses 0 to 100.
4639994a338SPaul Mackerras *
4643d2cea73SMilton Miller * This is used by all slaves, even those that did not find a matching
4653d2cea73SMilton Miller * paca in the secondary startup code.
4669994a338SPaul Mackerras *
4679994a338SPaul Mackerras * Physical (hardware) cpu id should be in r3.
4689994a338SPaul Mackerras */
4699994a338SPaul Mackerras_GLOBAL(kexec_wait)
4709994a338SPaul Mackerras	bl	1f
4719994a338SPaul Mackerras1:	mflr	r5
4729994a338SPaul Mackerras	addi	r5,r5,kexec_flag-1b
4739994a338SPaul Mackerras
4749994a338SPaul Mackerras99:	HMT_LOW
4759994a338SPaul Mackerras#ifdef CONFIG_KEXEC		/* use no memory without kexec */
4769994a338SPaul Mackerras	lwz	r4,0(r5)
4779994a338SPaul Mackerras	cmpwi	0,r4,0
4789994a338SPaul Mackerras	bnea	0x60
4799994a338SPaul Mackerras#endif
4809994a338SPaul Mackerras	b	99b
4819994a338SPaul Mackerras
4829994a338SPaul Mackerras/* this can be in text because we won't change it until we are
4839994a338SPaul Mackerras * running in real anyways
4849994a338SPaul Mackerras */
4859994a338SPaul Mackerraskexec_flag:
4869994a338SPaul Mackerras	.long	0
4879994a338SPaul Mackerras
4889994a338SPaul Mackerras
4899994a338SPaul Mackerras#ifdef CONFIG_KEXEC
4909994a338SPaul Mackerras
4919994a338SPaul Mackerras/* kexec_smp_wait(void)
4929994a338SPaul Mackerras *
4939994a338SPaul Mackerras * call with interrupts off
4949994a338SPaul Mackerras * note: this is a terminal routine, it does not save lr
4959994a338SPaul Mackerras *
4969994a338SPaul Mackerras * get phys id from paca
4979994a338SPaul Mackerras * switch to real mode
4983d2cea73SMilton Miller * mark the paca as no longer used
4999994a338SPaul Mackerras * join other cpus in kexec_wait(phys_id)
5009994a338SPaul Mackerras */
5019994a338SPaul Mackerras_GLOBAL(kexec_smp_wait)
5029994a338SPaul Mackerras	lhz	r3,PACAHWCPUID(r13)
5039994a338SPaul Mackerras	bl	real_mode
5043d2cea73SMilton Miller
5053d2cea73SMilton Miller	li	r4,KEXEC_STATE_REAL_MODE
5063d2cea73SMilton Miller	stb	r4,PACAKEXECSTATE(r13)
5073d2cea73SMilton Miller	SYNC
5083d2cea73SMilton Miller
509b1576fecSAnton Blanchard	b	kexec_wait
5109994a338SPaul Mackerras
5119994a338SPaul Mackerras/*
5129994a338SPaul Mackerras * switch to real mode (turn mmu off)
5139994a338SPaul Mackerras * we use the early kernel trick that the hardware ignores bits
5149994a338SPaul Mackerras * 0 and 1 (big endian) of the effective address in real mode
5159994a338SPaul Mackerras *
5169994a338SPaul Mackerras * don't overwrite r3 here, it is live for kexec_wait above.
5179994a338SPaul Mackerras */
5189994a338SPaul Mackerrasreal_mode:	/* assume normal blr return */
5199994a338SPaul Mackerras1:	li	r9,MSR_RI
5209994a338SPaul Mackerras	li	r10,MSR_DR|MSR_IR
5219994a338SPaul Mackerras	mflr	r11		/* return address to SRR0 */
5229994a338SPaul Mackerras	mfmsr	r12
5239994a338SPaul Mackerras	andc	r9,r12,r9
5249994a338SPaul Mackerras	andc	r10,r12,r10
5259994a338SPaul Mackerras
5269994a338SPaul Mackerras	mtmsrd	r9,1
5279994a338SPaul Mackerras	mtspr	SPRN_SRR1,r10
5289994a338SPaul Mackerras	mtspr	SPRN_SRR0,r11
5299994a338SPaul Mackerras	rfid
5309994a338SPaul Mackerras
5319994a338SPaul Mackerras
5329994a338SPaul Mackerras/*
5331767c8f3SMilton Miller * kexec_sequence(newstack, start, image, control, clear_all())
5349994a338SPaul Mackerras *
5359994a338SPaul Mackerras * does the grungy work with stack switching and real mode switches
5369994a338SPaul Mackerras * also does simple calls to other code
5379994a338SPaul Mackerras */
5389994a338SPaul Mackerras
5399994a338SPaul Mackerras_GLOBAL(kexec_sequence)
5409994a338SPaul Mackerras	mflr	r0
5419994a338SPaul Mackerras	std	r0,16(r1)
5429994a338SPaul Mackerras
5439994a338SPaul Mackerras	/* switch stacks to newstack -- &kexec_stack.stack */
5444ae2dcb6SKumar Gala	stdu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
5459994a338SPaul Mackerras	mr	r1,r3
5469994a338SPaul Mackerras
5479994a338SPaul Mackerras	li	r0,0
5489994a338SPaul Mackerras	std	r0,16(r1)
5499994a338SPaul Mackerras
5509994a338SPaul Mackerras	/* save regs for local vars on new stack.
5519994a338SPaul Mackerras	 * yes, we won't go back, but ...
5529994a338SPaul Mackerras	 */
5539994a338SPaul Mackerras	std	r31,-8(r1)
5549994a338SPaul Mackerras	std	r30,-16(r1)
5559994a338SPaul Mackerras	std	r29,-24(r1)
5569994a338SPaul Mackerras	std	r28,-32(r1)
5579994a338SPaul Mackerras	std	r27,-40(r1)
5589994a338SPaul Mackerras	std	r26,-48(r1)
5599994a338SPaul Mackerras	std	r25,-56(r1)
5609994a338SPaul Mackerras
5614ae2dcb6SKumar Gala	stdu	r1,-STACK_FRAME_OVERHEAD-64(r1)
5629994a338SPaul Mackerras
5639994a338SPaul Mackerras	/* save args into preserved regs */
5649994a338SPaul Mackerras	mr	r31,r3			/* newstack (both) */
5659994a338SPaul Mackerras	mr	r30,r4			/* start (real) */
5669994a338SPaul Mackerras	mr	r29,r5			/* image (virt) */
5679994a338SPaul Mackerras	mr	r28,r6			/* control, unused */
5689994a338SPaul Mackerras	mr	r27,r7			/* clear_all() fn desc */
5691767c8f3SMilton Miller	mr	r26,r8			/* spare */
5709994a338SPaul Mackerras	lhz	r25,PACAHWCPUID(r13)	/* get our phys cpu from paca */
5719994a338SPaul Mackerras
5729994a338SPaul Mackerras	/* disable interrupts, we are overwriting kernel data next */
5739994a338SPaul Mackerras	mfmsr	r3
5749994a338SPaul Mackerras	rlwinm	r3,r3,0,17,15
5759994a338SPaul Mackerras	mtmsrd	r3,1
5769994a338SPaul Mackerras
5779994a338SPaul Mackerras	/* copy dest pages, flush whole dest image */
5789994a338SPaul Mackerras	mr	r3,r29
579b1576fecSAnton Blanchard	bl	kexec_copy_flush	/* (image) */
5809994a338SPaul Mackerras
5819994a338SPaul Mackerras	/* turn off mmu */
5829994a338SPaul Mackerras	bl	real_mode
5839994a338SPaul Mackerras
584ee46a90bSMilton Miller	/* copy  0x100 bytes starting at start to 0 */
585ee46a90bSMilton Miller	li	r3,0
586ee46a90bSMilton Miller	mr	r4,r30		/* start, aka phys mem offset */
587ee46a90bSMilton Miller	li	r5,0x100
588ee46a90bSMilton Miller	li	r6,0
589b1576fecSAnton Blanchard	bl	copy_and_flush	/* (dest, src, copy limit, start offset) */
590ee46a90bSMilton Miller1:	/* assume normal blr return */
591ee46a90bSMilton Miller
592ee46a90bSMilton Miller	/* release other cpus to the new kernel secondary start at 0x60 */
593ee46a90bSMilton Miller	mflr	r5
594ee46a90bSMilton Miller	li	r6,1
595ee46a90bSMilton Miller	stw	r6,kexec_flag-1b(5)
596ee46a90bSMilton Miller
5979994a338SPaul Mackerras	/* clear out hardware hash page table and tlb */
598*cc7efbf9SAnton Blanchard#if !defined(_CALL_ELF) || _CALL_ELF != 2
599*cc7efbf9SAnton Blanchard	ld	r12,0(r27)		/* deref function descriptor */
600*cc7efbf9SAnton Blanchard#else
601*cc7efbf9SAnton Blanchard	mr	r12,r27
602*cc7efbf9SAnton Blanchard#endif
603*cc7efbf9SAnton Blanchard	mtctr	r12
6048d950cb8SGeoff Levand	bctrl				/* ppc_md.hpte_clear_all(void); */
6059994a338SPaul Mackerras
6069994a338SPaul Mackerras/*
6079994a338SPaul Mackerras *   kexec image calling is:
6089994a338SPaul Mackerras *      the first 0x100 bytes of the entry point are copied to 0
6099994a338SPaul Mackerras *
6109994a338SPaul Mackerras *      all slaves branch to slave = 0x60 (absolute)
6119994a338SPaul Mackerras *              slave(phys_cpu_id);
6129994a338SPaul Mackerras *
6139994a338SPaul Mackerras *      master goes to start = entry point
6149994a338SPaul Mackerras *              start(phys_cpu_id, start, 0);
6159994a338SPaul Mackerras *
6169994a338SPaul Mackerras *
6179994a338SPaul Mackerras *   a wrapper is needed to call existing kernels, here is an approximate
6189994a338SPaul Mackerras *   description of one method:
6199994a338SPaul Mackerras *
6209994a338SPaul Mackerras * v2: (2.6.10)
6219994a338SPaul Mackerras *   start will be near the boot_block (maybe 0x100 bytes before it?)
6229994a338SPaul Mackerras *   it will have a 0x60, which will b to boot_block, where it will wait
6239994a338SPaul Mackerras *   and 0 will store phys into struct boot-block and load r3 from there,
6249994a338SPaul Mackerras *   copy kernel 0-0x100 and tell slaves to back down to 0x60 again
6259994a338SPaul Mackerras *
6269994a338SPaul Mackerras * v1: (2.6.9)
6279994a338SPaul Mackerras *    boot block will have all cpus scanning device tree to see if they
6289994a338SPaul Mackerras *    are the boot cpu ?????
6299994a338SPaul Mackerras *    other device tree differences (prop sizes, va vs pa, etc)...
6309994a338SPaul Mackerras */
6319994a338SPaul Mackerras	mr	r3,r25	# my phys cpu
6329994a338SPaul Mackerras	mr	r4,r30	# start, aka phys mem offset
6339994a338SPaul Mackerras	mtlr	4
6349994a338SPaul Mackerras	li	r5,0
6351767c8f3SMilton Miller	blr	/* image->start(physid, image->start, 0); */
6369994a338SPaul Mackerras#endif /* CONFIG_KEXEC */
637