1/*
2 *  Low level routines for legacy iSeries support.
3 *
4 *  Extracted from head_64.S
5 *
6 *  PowerPC version
7 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
8 *
9 *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
10 *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
11 *  Adapted for Power Macintosh by Paul Mackerras.
12 *  Low-level exception handlers and MMU support
13 *  rewritten by Paul Mackerras.
14 *    Copyright (C) 1996 Paul Mackerras.
15 *
16 *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
17 *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
18 *
19 *  This file contains the low-level support and setup for the
20 *  PowerPC-64 platform, including trap and interrupt dispatch.
21 *
22 *  This program is free software; you can redistribute it and/or
23 *  modify it under the terms of the GNU General Public License
24 *  as published by the Free Software Foundation; either version
25 *  2 of the License, or (at your option) any later version.
26 */
27
28#include <asm/reg.h>
29#include <asm/ppc_asm.h>
30#include <asm/asm-offsets.h>
31#include <asm/thread_info.h>
32#include <asm/ptrace.h>
33#include <asm/cputable.h>
34
35#include "exception.h"
36
37	.text
38
39	.globl system_reset_iSeries
40system_reset_iSeries:
41	bl	.relative_toc
42	mfspr	r13,SPRN_SPRG3		/* Get alpaca address */
43	LOAD_REG_ADDR(r23, alpaca)
44	li	r0,ALPACA_SIZE
45	sub	r23,r13,r23
46	divdu	r24,r23,r0		/* r24 has cpu number */
47	cmpwi	0,r24,0			/* Are we processor 0? */
48	bne	1f
49	LOAD_REG_ADDR(r13, boot_paca)
50	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */
51	mfmsr	r23
52	ori	r23,r23,MSR_RI
53	mtmsrd	r23			/* RI on */
54	b	.__start_initialization_iSeries	/* Start up the first processor */
551:	mfspr	r4,SPRN_CTRLF
56	li	r5,CTRL_RUNLATCH	/* Turn off the run light */
57	andc	r4,r4,r5
58	mtspr	SPRN_CTRLT,r4
59
60/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
61/* In the UP case we'll yield() later, and we will not access the paca anyway */
62#ifdef CONFIG_SMP
631:
64	HMT_LOW
65	LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
66	ld	r23,0(r23)
67	sync
68	LOAD_REG_ADDR(r3,current_set)
69	sldi	r28,r24,3		/* get current_set[cpu#] */
70	ldx	r3,r3,r28
71	addi	r1,r3,THREAD_SIZE
72	subi	r1,r1,STACK_FRAME_OVERHEAD
73
74	cmpwi	0,r23,0			/* Keep poking the Hypervisor until */
75	bne	2f			/* we're released */
76	/* Let the Hypervisor know we are alive */
77	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
78	lis	r3,0x8002
79	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
80	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
81	sc				/* Invoke the hypervisor via a system call */
82	b	1b
83#endif
84
852:
86	/* Load our paca now that it's been allocated */
87	LOAD_REG_ADDR(r13, paca)
88	ld	r13,0(r13)
89	mulli	r0,r24,PACA_SIZE
90	add	r13,r13,r0
91	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */
92	mfmsr	r23
93	ori	r23,r23,MSR_RI
94	mtmsrd	r23			/* RI on */
95
96	HMT_LOW
97#ifdef CONFIG_SMP
98	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor
99					 * should start */
100	sync
101	LOAD_REG_ADDR(r3,current_set)
102	sldi	r28,r24,3		/* get current_set[cpu#] */
103	ldx	r3,r3,r28
104	addi	r1,r3,THREAD_SIZE
105	subi	r1,r1,STACK_FRAME_OVERHEAD
106
107	cmpwi	0,r23,0
108	beq	iSeries_secondary_smp_loop	/* Loop until told to go */
109	b	__secondary_start		/* Loop until told to go */
110iSeries_secondary_smp_loop:
111	/* Let the Hypervisor know we are alive */
112	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
113	lis	r3,0x8002
114	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
115#else /* CONFIG_SMP */
116	/* Yield the processor.  This is required for non-SMP kernels
117		which are running on multi-threaded machines. */
118	lis	r3,0x8000
119	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */
120	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */
121	li	r4,0			/* "yield timed" */
122	li	r5,-1			/* "yield forever" */
123#endif /* CONFIG_SMP */
124	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
125	sc				/* Invoke the hypervisor via a system call */
126	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
127	b	2b			/* If SMP not configured, secondaries
128					 * loop forever */
129
130/***  ISeries-LPAR interrupt handlers ***/
131
132	STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)
133
134	.globl data_access_iSeries
135data_access_iSeries:
136	mtspr	SPRN_SPRG_SCRATCH0,r13
137BEGIN_FTR_SECTION
138	mfspr	r13,SPRN_SPRG_PACA
139	std	r9,PACA_EXSLB+EX_R9(r13)
140	std	r10,PACA_EXSLB+EX_R10(r13)
141	mfspr	r10,SPRN_DAR
142	mfspr	r9,SPRN_DSISR
143	srdi	r10,r10,60
144	rlwimi	r10,r9,16,0x20
145	mfcr	r9
146	cmpwi	r10,0x2c
147	beq	.do_stab_bolted_iSeries
148	ld	r10,PACA_EXSLB+EX_R10(r13)
149	std	r11,PACA_EXGEN+EX_R11(r13)
150	ld	r11,PACA_EXSLB+EX_R9(r13)
151	std	r12,PACA_EXGEN+EX_R12(r13)
152	mfspr	r12,SPRN_SPRG_SCRATCH0
153	std	r10,PACA_EXGEN+EX_R10(r13)
154	std	r11,PACA_EXGEN+EX_R9(r13)
155	std	r12,PACA_EXGEN+EX_R13(r13)
156	EXCEPTION_PROLOG_ISERIES_1
157FTR_SECTION_ELSE
158	EXCEPTION_PROLOG_1(PACA_EXGEN)
159	EXCEPTION_PROLOG_ISERIES_1
160ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
161	b	data_access_common
162
163.do_stab_bolted_iSeries:
164	std	r11,PACA_EXSLB+EX_R11(r13)
165	std	r12,PACA_EXSLB+EX_R12(r13)
166	mfspr	r10,SPRN_SPRG_SCRATCH0
167	std	r10,PACA_EXSLB+EX_R13(r13)
168	EXCEPTION_PROLOG_ISERIES_1
169	b	.do_stab_bolted
170
171	.globl	data_access_slb_iSeries
172data_access_slb_iSeries:
173	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */
174	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */
175	std	r3,PACA_EXSLB+EX_R3(r13)
176	mfspr	r3,SPRN_DAR
177	std	r9,PACA_EXSLB+EX_R9(r13)
178	mfcr	r9
179#ifdef __DISABLED__
180	cmpdi	r3,0
181	bge	slb_miss_user_iseries
182#endif
183	std	r10,PACA_EXSLB+EX_R10(r13)
184	std	r11,PACA_EXSLB+EX_R11(r13)
185	std	r12,PACA_EXSLB+EX_R12(r13)
186	mfspr	r10,SPRN_SPRG_SCRATCH0
187	std	r10,PACA_EXSLB+EX_R13(r13)
188	ld	r12,PACALPPACAPTR(r13)
189	ld	r12,LPPACASRR1(r12)
190	b	.slb_miss_realmode
191
192	STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)
193
194	.globl	instruction_access_slb_iSeries
195instruction_access_slb_iSeries:
196	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */
197	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */
198	std	r3,PACA_EXSLB+EX_R3(r13)
199	ld	r3,PACALPPACAPTR(r13)
200	ld	r3,LPPACASRR0(r3)	/* get SRR0 value */
201	std	r9,PACA_EXSLB+EX_R9(r13)
202	mfcr	r9
203#ifdef __DISABLED__
204	cmpdi	r3,0
205	bge	slb_miss_user_iseries
206#endif
207	std	r10,PACA_EXSLB+EX_R10(r13)
208	std	r11,PACA_EXSLB+EX_R11(r13)
209	std	r12,PACA_EXSLB+EX_R12(r13)
210	mfspr	r10,SPRN_SPRG_SCRATCH0
211	std	r10,PACA_EXSLB+EX_R13(r13)
212	ld	r12,PACALPPACAPTR(r13)
213	ld	r12,LPPACASRR1(r12)
214	b	.slb_miss_realmode
215
216#ifdef __DISABLED__
217slb_miss_user_iseries:
218	std	r10,PACA_EXGEN+EX_R10(r13)
219	std	r11,PACA_EXGEN+EX_R11(r13)
220	std	r12,PACA_EXGEN+EX_R12(r13)
221	mfspr	r10,SPRG_SCRATCH0
222	ld	r11,PACA_EXSLB+EX_R9(r13)
223	ld	r12,PACA_EXSLB+EX_R3(r13)
224	std	r10,PACA_EXGEN+EX_R13(r13)
225	std	r11,PACA_EXGEN+EX_R9(r13)
226	std	r12,PACA_EXGEN+EX_R3(r13)
227	EXCEPTION_PROLOG_ISERIES_1
228	b	slb_miss_user_common
229#endif
230
231	MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)
232	STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)
233	STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)
234	STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)
235	MASKABLE_EXCEPTION_ISERIES(decrementer)
236	STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)
237	STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)
238
239	.globl	system_call_iSeries
240system_call_iSeries:
241	mr	r9,r13
242	mfspr	r13,SPRN_SPRG_PACA
243	EXCEPTION_PROLOG_ISERIES_1
244	b	system_call_common
245
246	STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)
247	STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)
248	STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)
249
250decrementer_iSeries_masked:
251	/* We may not have a valid TOC pointer in here. */
252	li	r11,1
253	ld	r12,PACALPPACAPTR(r13)
254	stb	r11,LPPACADECRINT(r12)
255	li	r12,-1
256	clrldi	r12,r12,33	/* set DEC to 0x7fffffff */
257	mtspr	SPRN_DEC,r12
258	/* fall through */
259
260hardware_interrupt_iSeries_masked:
261	mtcrf	0x80,r9		/* Restore regs */
262	ld	r12,PACALPPACAPTR(r13)
263	ld	r11,LPPACASRR0(r12)
264	ld	r12,LPPACASRR1(r12)
265	mtspr	SPRN_SRR0,r11
266	mtspr	SPRN_SRR1,r12
267	ld	r9,PACA_EXGEN+EX_R9(r13)
268	ld	r10,PACA_EXGEN+EX_R10(r13)
269	ld	r11,PACA_EXGEN+EX_R11(r13)
270	ld	r12,PACA_EXGEN+EX_R12(r13)
271	ld	r13,PACA_EXGEN+EX_R13(r13)
272	rfid
273	b	.	/* prevent speculative execution */
274
275_INIT_STATIC(__start_initialization_iSeries)
276	/* Clear out the BSS */
277	LOAD_REG_ADDR(r11,__bss_stop)
278	LOAD_REG_ADDR(r8,__bss_start)
279	sub	r11,r11,r8		/* bss size			*/
280	addi	r11,r11,7		/* round up to an even double word */
281	rldicl. r11,r11,61,3		/* shift right by 3		*/
282	beq	4f
283	addi	r8,r8,-8
284	li	r0,0
285	mtctr	r11			/* zero this many doublewords	*/
2863:	stdu	r0,8(r8)
287	bdnz	3b
2884:
289	LOAD_REG_ADDR(r1,init_thread_union)
290	addi	r1,r1,THREAD_SIZE
291	li	r0,0
292	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
293
294	bl	.iSeries_early_setup
295	bl	.early_setup
296
297	/* relocation is on at this point */
298
299	b	.start_here_common
300