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#include <asm/mmu.h>
35
36#include "exception.h"
37
38	.text
39
40	.globl system_reset_iSeries
41system_reset_iSeries:
42	bl	.relative_toc
43	mfspr	r13,SPRN_SPRG3		/* Get alpaca address */
44	LOAD_REG_ADDR(r23, alpaca)
45	li	r0,ALPACA_SIZE
46	sub	r23,r13,r23
47	divdu	r24,r23,r0		/* r24 has cpu number */
48	cmpwi	0,r24,0			/* Are we processor 0? */
49	bne	1f
50	LOAD_REG_ADDR(r13, boot_paca)
51	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */
52	mfmsr	r23
53	ori	r23,r23,MSR_RI
54	mtmsrd	r23			/* RI on */
55	b	.__start_initialization_iSeries	/* Start up the first processor */
561:	mfspr	r4,SPRN_CTRLF
57	li	r5,CTRL_RUNLATCH	/* Turn off the run light */
58	andc	r4,r4,r5
59	mtspr	SPRN_CTRLT,r4
60
61/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
62/* In the UP case we'll yield() later, and we will not access the paca anyway */
63#ifdef CONFIG_SMP
64iSeries_secondary_wait_paca:
65	HMT_LOW
66	LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
67	ld	r23,0(r23)
68
69	cmpdi	0,r23,0
70	bne	2f			/* go on when the master is ready */
71
72	/* Keep poking the Hypervisor until we're released */
73	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
74	lis	r3,0x8002
75	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
76	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
77	sc				/* Invoke the hypervisor via a system call */
78	b	iSeries_secondary_wait_paca
79
802:
81	HMT_MEDIUM
82	sync
83
84	LOAD_REG_ADDR(r3, nr_cpu_ids)	/* get number of pacas allocated */
85	lwz	r3,0(r3)		/* nr_cpus= or NR_CPUS can limit */
86	cmpld	0,r24,r3		/* is our cpu number allocated? */
87	bge	iSeries_secondary_yield	/* no, yield forever */
88
89	/* Load our paca now that it's been allocated */
90	LOAD_REG_ADDR(r13, paca)
91	ld	r13,0(r13)
92	mulli	r0,r24,PACA_SIZE
93	add	r13,r13,r0
94	mtspr	SPRN_SPRG_PACA,r13	/* Save it away for the future */
95	mfmsr	r23
96	ori	r23,r23,MSR_RI
97	mtmsrd	r23			/* RI on */
98
99iSeries_secondary_smp_loop:
100	lbz	r23,PACAPROCSTART(r13)	/* Test if this processor
101					 * should start */
102	cmpwi	0,r23,0
103	bne	3f			/* go on when we are told */
104
105	HMT_LOW
106	/* Let the Hypervisor know we are alive */
107	/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
108	lis	r3,0x8002
109	rldicr	r3,r3,32,15		/* r0 = (r3 << 32) & 0xffff000000000000 */
110	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
111	sc				/* Invoke the hypervisor via a system call */
112	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
113	b	iSeries_secondary_smp_loop /* wait for signal to start */
114
1153:
116	HMT_MEDIUM
117	sync
118	LOAD_REG_ADDR(r3,current_set)
119	sldi	r28,r24,3		/* get current_set[cpu#] */
120	ldx	r3,r3,r28
121	addi	r1,r3,THREAD_SIZE
122	subi	r1,r1,STACK_FRAME_OVERHEAD
123
124	b	__secondary_start		/* Loop until told to go */
125#endif /* CONFIG_SMP */
126
127iSeries_secondary_yield:
128	/* Yield the processor.  This is required for non-SMP kernels
129		which are running on multi-threaded machines. */
130	HMT_LOW
131	lis	r3,0x8000
132	rldicr	r3,r3,32,15		/* r3 = (r3 << 32) & 0xffff000000000000 */
133	addi	r3,r3,18		/* r3 = 0x8000000000000012 which is "yield" */
134	li	r4,0			/* "yield timed" */
135	li	r5,-1			/* "yield forever" */
136	li	r0,-1			/* r0=-1 indicates a Hypervisor call */
137	sc				/* Invoke the hypervisor via a system call */
138	mfspr	r13,SPRN_SPRG_PACA	/* Put r13 back ???? */
139	b	iSeries_secondary_yield	/* If SMP not configured, secondaries
140					 * loop forever */
141
142/***  ISeries-LPAR interrupt handlers ***/
143
144	STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)
145
146	.globl data_access_iSeries
147data_access_iSeries:
148	mtspr	SPRN_SPRG_SCRATCH0,r13
149BEGIN_FTR_SECTION
150	mfspr	r13,SPRN_SPRG_PACA
151	std	r9,PACA_EXSLB+EX_R9(r13)
152	std	r10,PACA_EXSLB+EX_R10(r13)
153	mfspr	r10,SPRN_DAR
154	mfspr	r9,SPRN_DSISR
155	srdi	r10,r10,60
156	rlwimi	r10,r9,16,0x20
157	mfcr	r9
158	cmpwi	r10,0x2c
159	beq	.do_stab_bolted_iSeries
160	ld	r10,PACA_EXSLB+EX_R10(r13)
161	std	r11,PACA_EXGEN+EX_R11(r13)
162	ld	r11,PACA_EXSLB+EX_R9(r13)
163	std	r12,PACA_EXGEN+EX_R12(r13)
164	mfspr	r12,SPRN_SPRG_SCRATCH0
165	std	r10,PACA_EXGEN+EX_R10(r13)
166	std	r11,PACA_EXGEN+EX_R9(r13)
167	std	r12,PACA_EXGEN+EX_R13(r13)
168	EXCEPTION_PROLOG_ISERIES_1
169FTR_SECTION_ELSE
170	EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0)
171	EXCEPTION_PROLOG_ISERIES_1
172ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)
173	b	data_access_common
174
175.do_stab_bolted_iSeries:
176	std	r11,PACA_EXSLB+EX_R11(r13)
177	std	r12,PACA_EXSLB+EX_R12(r13)
178	mfspr	r10,SPRN_SPRG_SCRATCH0
179	std	r10,PACA_EXSLB+EX_R13(r13)
180	EXCEPTION_PROLOG_ISERIES_1
181	b	.do_stab_bolted
182
183	.globl	data_access_slb_iSeries
184data_access_slb_iSeries:
185	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */
186	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */
187	std	r3,PACA_EXSLB+EX_R3(r13)
188	mfspr	r3,SPRN_DAR
189	std	r9,PACA_EXSLB+EX_R9(r13)
190	mfcr	r9
191#ifdef __DISABLED__
192	cmpdi	r3,0
193	bge	slb_miss_user_iseries
194#endif
195	std	r10,PACA_EXSLB+EX_R10(r13)
196	std	r11,PACA_EXSLB+EX_R11(r13)
197	std	r12,PACA_EXSLB+EX_R12(r13)
198	mfspr	r10,SPRN_SPRG_SCRATCH0
199	std	r10,PACA_EXSLB+EX_R13(r13)
200	ld	r12,PACALPPACAPTR(r13)
201	ld	r12,LPPACASRR1(r12)
202	b	.slb_miss_realmode
203
204	STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)
205
206	.globl	instruction_access_slb_iSeries
207instruction_access_slb_iSeries:
208	mtspr	SPRN_SPRG_SCRATCH0,r13	/* save r13 */
209	mfspr	r13,SPRN_SPRG_PACA	/* get paca address into r13 */
210	std	r3,PACA_EXSLB+EX_R3(r13)
211	ld	r3,PACALPPACAPTR(r13)
212	ld	r3,LPPACASRR0(r3)	/* get SRR0 value */
213	std	r9,PACA_EXSLB+EX_R9(r13)
214	mfcr	r9
215#ifdef __DISABLED__
216	cmpdi	r3,0
217	bge	slb_miss_user_iseries
218#endif
219	std	r10,PACA_EXSLB+EX_R10(r13)
220	std	r11,PACA_EXSLB+EX_R11(r13)
221	std	r12,PACA_EXSLB+EX_R12(r13)
222	mfspr	r10,SPRN_SPRG_SCRATCH0
223	std	r10,PACA_EXSLB+EX_R13(r13)
224	ld	r12,PACALPPACAPTR(r13)
225	ld	r12,LPPACASRR1(r12)
226	b	.slb_miss_realmode
227
228#ifdef __DISABLED__
229slb_miss_user_iseries:
230	std	r10,PACA_EXGEN+EX_R10(r13)
231	std	r11,PACA_EXGEN+EX_R11(r13)
232	std	r12,PACA_EXGEN+EX_R12(r13)
233	mfspr	r10,SPRG_SCRATCH0
234	ld	r11,PACA_EXSLB+EX_R9(r13)
235	ld	r12,PACA_EXSLB+EX_R3(r13)
236	std	r10,PACA_EXGEN+EX_R13(r13)
237	std	r11,PACA_EXGEN+EX_R9(r13)
238	std	r12,PACA_EXGEN+EX_R3(r13)
239	EXCEPTION_PROLOG_ISERIES_1
240	b	slb_miss_user_common
241#endif
242
243	MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)
244	STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)
245	STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)
246	STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)
247	MASKABLE_EXCEPTION_ISERIES(decrementer)
248	STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)
249	STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)
250
251	.globl	system_call_iSeries
252system_call_iSeries:
253	mr	r9,r13
254	mfspr	r13,SPRN_SPRG_PACA
255	EXCEPTION_PROLOG_ISERIES_1
256	b	system_call_common
257
258	STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)
259	STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)
260	STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)
261
262decrementer_iSeries_masked:
263	/* We may not have a valid TOC pointer in here. */
264	li	r11,1
265	ld	r12,PACALPPACAPTR(r13)
266	stb	r11,LPPACADECRINT(r12)
267	li	r12,-1
268	clrldi	r12,r12,33	/* set DEC to 0x7fffffff */
269	mtspr	SPRN_DEC,r12
270	/* fall through */
271
272hardware_interrupt_iSeries_masked:
273	mtcrf	0x80,r9		/* Restore regs */
274	ld	r12,PACALPPACAPTR(r13)
275	ld	r11,LPPACASRR0(r12)
276	ld	r12,LPPACASRR1(r12)
277	mtspr	SPRN_SRR0,r11
278	mtspr	SPRN_SRR1,r12
279	ld	r9,PACA_EXGEN+EX_R9(r13)
280	ld	r10,PACA_EXGEN+EX_R10(r13)
281	ld	r11,PACA_EXGEN+EX_R11(r13)
282	ld	r12,PACA_EXGEN+EX_R12(r13)
283	ld	r13,PACA_EXGEN+EX_R13(r13)
284	rfid
285	b	.	/* prevent speculative execution */
286
287_INIT_STATIC(__start_initialization_iSeries)
288	/* Clear out the BSS */
289	LOAD_REG_ADDR(r11,__bss_stop)
290	LOAD_REG_ADDR(r8,__bss_start)
291	sub	r11,r11,r8		/* bss size			*/
292	addi	r11,r11,7		/* round up to an even double word */
293	rldicl. r11,r11,61,3		/* shift right by 3		*/
294	beq	4f
295	addi	r8,r8,-8
296	li	r0,0
297	mtctr	r11			/* zero this many doublewords	*/
2983:	stdu	r0,8(r8)
299	bdnz	3b
3004:
301	LOAD_REG_ADDR(r1,init_thread_union)
302	addi	r1,r1,THREAD_SIZE
303	li	r0,0
304	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
305
306	bl	.iSeries_early_setup
307	bl	.early_setup
308
309	/* relocation is on at this point */
310
311	b	.start_here_common
312