| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * | 
 | 3 |  * This file is subject to the terms and conditions of the GNU General Public | 
 | 4 |  * License.  See the file "COPYING" in the main directory of this archive | 
 | 5 |  * for more details. | 
 | 6 |  * | 
 | 7 |  * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) | 
 | 8 |  * | 
 | 9 |  */ | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 10 |  | 
| Kyle McMartin | 6c86cb8 | 2008-07-28 22:52:18 -0400 | [diff] [blame] | 11 | #include <asm/pdc.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 | #include <asm/psw.h> | 
| Grant Grundler | 896a375 | 2005-10-21 22:40:07 -0400 | [diff] [blame] | 13 | #include <asm/assembly.h> | 
| Kyle McMartin | 6c86cb8 | 2008-07-28 22:52:18 -0400 | [diff] [blame] | 14 | #include <asm/asm-offsets.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 |  | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 16 | #include <linux/linkage.h> | 
 | 17 |  | 
| Kyle McMartin | 6c86cb8 | 2008-07-28 22:52:18 -0400 | [diff] [blame] | 18 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | 	.section	.bss | 
| Kyle McMartin | 6c86cb8 | 2008-07-28 22:52:18 -0400 | [diff] [blame] | 20 |  | 
 | 21 | 	.export pdc_result | 
 | 22 | 	.export pdc_result2 | 
 | 23 | 	.align 8 | 
 | 24 | pdc_result: | 
 | 25 | 	.block	ASM_PDC_RESULT_SIZE | 
 | 26 | pdc_result2: | 
 | 27 | 	.block	ASM_PDC_RESULT_SIZE | 
 | 28 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | 	.export real_stack | 
 | 30 | 	.export real32_stack | 
 | 31 | 	.export real64_stack | 
 | 32 | 	.align	64 | 
 | 33 | real_stack: | 
 | 34 | real32_stack: | 
 | 35 | real64_stack: | 
 | 36 | 	.block	8192 | 
 | 37 |  | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 38 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | #  define REG_SZ 8 | 
 | 40 | #else | 
 | 41 | #  define REG_SZ 4 | 
 | 42 | #endif | 
 | 43 |  | 
 | 44 | #define N_SAVED_REGS 9 | 
 | 45 |  | 
 | 46 | save_cr_space: | 
 | 47 | 	.block	REG_SZ * N_SAVED_REGS | 
 | 48 | save_cr_end: | 
 | 49 |  | 
 | 50 |  | 
 | 51 | /************************ 32-bit real-mode calls ***********************/ | 
 | 52 | /* This can be called in both narrow and wide kernels */ | 
 | 53 |  | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 54 | 	.text | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 55 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | 	/* unsigned long real32_call_asm(unsigned int *sp, | 
 | 57 | 	 *		unsigned int *arg0p, | 
 | 58 | 	 *		unsigned int iodc_fn) | 
 | 59 | 	 *	sp is value of stack pointer to adopt before calling PDC (virt) | 
 | 60 | 	 *	arg0p points to where saved arg values may be found | 
 | 61 | 	 *	iodc_fn is the IODC function to call | 
 | 62 | 	 */ | 
 | 63 |  | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 64 | ENTRY(real32_call_asm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | 	STREG	%rp, -RP_OFFSET(%sp)	/* save RP */ | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 66 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | 	callee_save | 
 | 68 | 	ldo	2*REG_SZ(%sp), %sp	/* room for a couple more saves */ | 
 | 69 | 	STREG	%r27, -1*REG_SZ(%sp) | 
 | 70 | 	STREG	%r29, -2*REG_SZ(%sp) | 
 | 71 | #endif | 
 | 72 | 	STREG	%sp, -REG_SZ(%arg0)	/* save SP on real-mode stack */ | 
 | 73 | 	copy	%arg0, %sp		/* adopt the real-mode SP */ | 
 | 74 |  | 
 | 75 | 	/* save iodc_fn */ | 
 | 76 | 	copy	%arg2, %r31 | 
 | 77 |  | 
 | 78 | 	/* load up the arg registers from the saved arg area */ | 
 | 79 | 	/* 32-bit calling convention passes first 4 args in registers */ | 
 | 80 | 	ldw	0(%arg1), %arg0		/* note overwriting arg0 */ | 
 | 81 | 	ldw	-8(%arg1), %arg2 | 
 | 82 | 	ldw	-12(%arg1), %arg3 | 
 | 83 | 	ldw	-4(%arg1), %arg1	/* obviously must do this one last! */ | 
 | 84 |  | 
 | 85 | 	tophys_r1  %sp | 
 | 86 |  | 
 | 87 | 	b,l	rfi_virt2real,%r2 | 
 | 88 | 	nop | 
 | 89 |  | 
 | 90 | 	b,l	save_control_regs,%r2		/* modifies r1, r2, r28 */ | 
 | 91 | 	nop | 
 | 92 |  | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 93 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | 	rsm	PSW_SM_W, %r0		/* go narrow */ | 
 | 95 | #endif | 
 | 96 |  | 
 | 97 | 	load32	PA(ric_ret), %r2 | 
 | 98 | 	bv	0(%r31) | 
 | 99 | 	nop | 
 | 100 | ric_ret: | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 101 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 102 | 	ssm	PSW_SM_W, %r0		/* go wide */ | 
 | 103 | #endif | 
 | 104 | 	/* restore CRs before going virtual in case we page fault */ | 
 | 105 | 	b,l	restore_control_regs, %r2	/* modifies r1, r2, r26 */ | 
 | 106 | 	nop | 
 | 107 |  | 
 | 108 | 	b,l	rfi_real2virt,%r2 | 
 | 109 | 	nop | 
 | 110 |  | 
 | 111 | 	tovirt_r1 %sp | 
 | 112 | 	LDREG	-REG_SZ(%sp), %sp	/* restore SP */ | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 113 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | 	LDREG	-1*REG_SZ(%sp), %r27 | 
 | 115 | 	LDREG	-2*REG_SZ(%sp), %r29 | 
 | 116 | 	ldo	-2*REG_SZ(%sp), %sp | 
 | 117 | 	callee_rest | 
 | 118 | #endif | 
 | 119 | 	LDREG	-RP_OFFSET(%sp), %rp	/* restore RP */ | 
 | 120 | 	bv	0(%rp) | 
 | 121 | 	nop | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 122 | ENDPROC(real32_call_asm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 |  | 
 | 124 |  | 
 | 125 | #  define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) | 
 | 126 | #  define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r | 
 | 127 |  | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 128 | 	.text | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | save_control_regs: | 
 | 130 | 	load32	PA(save_cr_space), %r28 | 
 | 131 | 	PUSH_CR(%cr24, %r28) | 
 | 132 | 	PUSH_CR(%cr25, %r28) | 
 | 133 | 	PUSH_CR(%cr26, %r28) | 
 | 134 | 	PUSH_CR(%cr27, %r28) | 
 | 135 | 	PUSH_CR(%cr28, %r28) | 
 | 136 | 	PUSH_CR(%cr29, %r28) | 
 | 137 | 	PUSH_CR(%cr30, %r28) | 
 | 138 | 	PUSH_CR(%cr31, %r28) | 
 | 139 | 	PUSH_CR(%cr15, %r28) | 
 | 140 | 	bv 0(%r2) | 
 | 141 | 	nop | 
 | 142 |  | 
 | 143 | restore_control_regs: | 
 | 144 | 	load32	PA(save_cr_end), %r26 | 
 | 145 | 	POP_CR(%cr15, %r26) | 
 | 146 | 	POP_CR(%cr31, %r26) | 
 | 147 | 	POP_CR(%cr30, %r26) | 
 | 148 | 	POP_CR(%cr29, %r26) | 
 | 149 | 	POP_CR(%cr28, %r26) | 
 | 150 | 	POP_CR(%cr27, %r26) | 
 | 151 | 	POP_CR(%cr26, %r26) | 
 | 152 | 	POP_CR(%cr25, %r26) | 
 | 153 | 	POP_CR(%cr24, %r26) | 
 | 154 | 	bv 0(%r2) | 
 | 155 | 	nop | 
 | 156 |  | 
 | 157 | /* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for | 
 | 158 |  * more general-purpose use by the several places which need RFIs | 
 | 159 |  */ | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 160 | 	.text | 
| Grant Grundler | e55fb3e | 2005-10-21 22:56:53 -0400 | [diff] [blame] | 161 | 	.align 128 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 162 | rfi_virt2real: | 
 | 163 | 	/* switch to real mode... */ | 
| Grant Grundler | 896a375 | 2005-10-21 22:40:07 -0400 | [diff] [blame] | 164 | 	rsm		PSW_SM_I,%r0 | 
 | 165 | 	load32		PA(rfi_v2r_1), %r1 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 166 | 	nop | 
 | 167 | 	nop | 
 | 168 | 	nop | 
 | 169 | 	nop | 
 | 170 | 	nop | 
 | 171 | 	 | 
| Grant Grundler | 896a375 | 2005-10-21 22:40:07 -0400 | [diff] [blame] | 172 | 	rsm             PSW_SM_Q,%r0  /* disable Q & I bits to load iia queue */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | 	mtctl		%r0, %cr17	/* Clear IIASQ tail */ | 
 | 174 | 	mtctl		%r0, %cr17	/* Clear IIASQ head */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 | 	mtctl		%r1, %cr18	/* IIAOQ head */ | 
 | 176 | 	ldo		4(%r1), %r1 | 
 | 177 | 	mtctl		%r1, %cr18	/* IIAOQ tail */ | 
 | 178 | 	load32          REAL_MODE_PSW, %r1 | 
 | 179 | 	mtctl		%r1, %cr22 | 
 | 180 | 	rfi | 
 | 181 | 	 | 
 | 182 | 	nop | 
 | 183 | 	nop | 
 | 184 | 	nop | 
 | 185 | 	nop | 
 | 186 | 	nop | 
 | 187 | 	nop | 
 | 188 | 	nop | 
 | 189 | 	nop | 
 | 190 | rfi_v2r_1: | 
 | 191 | 	tophys_r1 %r2 | 
 | 192 | 	bv	0(%r2) | 
 | 193 | 	nop | 
 | 194 |  | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 195 | 	.text | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 | 	.align 128 | 
 | 197 | rfi_real2virt: | 
| Grant Grundler | 896a375 | 2005-10-21 22:40:07 -0400 | [diff] [blame] | 198 | 	rsm		PSW_SM_I,%r0 | 
 | 199 | 	load32		(rfi_r2v_1), %r1 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 200 | 	nop | 
 | 201 | 	nop | 
 | 202 | 	nop | 
 | 203 | 	nop | 
 | 204 | 	nop | 
 | 205 | 	 | 
 | 206 | 	rsm             PSW_SM_Q,%r0    /* disable Q bit to load iia queue */ | 
 | 207 | 	mtctl		%r0, %cr17	/* Clear IIASQ tail */ | 
 | 208 | 	mtctl		%r0, %cr17	/* Clear IIASQ head */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 209 | 	mtctl		%r1, %cr18	/* IIAOQ head */ | 
 | 210 | 	ldo		4(%r1), %r1 | 
 | 211 | 	mtctl		%r1, %cr18	/* IIAOQ tail */ | 
 | 212 | 	load32		KERNEL_PSW, %r1 | 
 | 213 | 	mtctl		%r1, %cr22 | 
 | 214 | 	rfi | 
 | 215 | 	 | 
 | 216 | 	nop | 
 | 217 | 	nop | 
 | 218 | 	nop | 
 | 219 | 	nop | 
 | 220 | 	nop | 
 | 221 | 	nop | 
 | 222 | 	nop | 
 | 223 | 	nop | 
 | 224 | rfi_r2v_1: | 
 | 225 | 	tovirt_r1 %r2 | 
 | 226 | 	bv	0(%r2) | 
 | 227 | 	nop | 
 | 228 |  | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 229 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 230 |  | 
 | 231 | /************************ 64-bit real-mode calls ***********************/ | 
 | 232 | /* This is only usable in wide kernels right now and will probably stay so */ | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 233 | 	.text | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 234 | 	/* unsigned long real64_call_asm(unsigned long *sp, | 
 | 235 | 	 *		unsigned long *arg0p, | 
 | 236 | 	 *		unsigned long fn) | 
 | 237 | 	 *	sp is value of stack pointer to adopt before calling PDC (virt) | 
 | 238 | 	 *	arg0p points to where saved arg values may be found | 
 | 239 | 	 *	iodc_fn is the IODC function to call | 
 | 240 | 	 */ | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 241 | ENTRY(real64_call_asm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 242 | 	std	%rp, -0x10(%sp)		/* save RP */ | 
 | 243 | 	std	%sp, -8(%arg0)		/* save SP on real-mode stack */ | 
 | 244 | 	copy	%arg0, %sp		/* adopt the real-mode SP */ | 
 | 245 |  | 
 | 246 | 	/* save fn */ | 
 | 247 | 	copy	%arg2, %r31 | 
 | 248 |  | 
 | 249 | 	/* set up the new ap */ | 
 | 250 | 	ldo	64(%arg1), %r29 | 
 | 251 |  | 
 | 252 | 	/* load up the arg registers from the saved arg area */ | 
 | 253 | 	/* 32-bit calling convention passes first 4 args in registers */ | 
 | 254 | 	ldd	0*REG_SZ(%arg1), %arg0		/* note overwriting arg0 */ | 
 | 255 | 	ldd	2*REG_SZ(%arg1), %arg2 | 
 | 256 | 	ldd	3*REG_SZ(%arg1), %arg3 | 
 | 257 | 	ldd	4*REG_SZ(%arg1), %r22 | 
 | 258 | 	ldd	5*REG_SZ(%arg1), %r21 | 
 | 259 | 	ldd	6*REG_SZ(%arg1), %r20 | 
 | 260 | 	ldd	7*REG_SZ(%arg1), %r19 | 
 | 261 | 	ldd	1*REG_SZ(%arg1), %arg1		/* do this one last! */ | 
 | 262 |  | 
 | 263 | 	tophys_r1 %sp | 
 | 264 |  | 
 | 265 | 	b,l	rfi_virt2real,%r2 | 
 | 266 | 	nop | 
 | 267 |  | 
 | 268 | 	b,l	save_control_regs,%r2		/* modifies r1, r2, r28 */ | 
 | 269 | 	nop | 
 | 270 |  | 
 | 271 | 	load32	PA(r64_ret), %r2 | 
 | 272 | 	bv	0(%r31) | 
 | 273 | 	nop | 
 | 274 | r64_ret: | 
 | 275 | 	/* restore CRs before going virtual in case we page fault */ | 
 | 276 | 	b,l	restore_control_regs, %r2	/* modifies r1, r2, r26 */ | 
 | 277 | 	nop | 
 | 278 |  | 
 | 279 | 	b,l	rfi_real2virt,%r2 | 
 | 280 | 	nop | 
 | 281 |  | 
 | 282 | 	tovirt_r1 %sp | 
 | 283 | 	ldd	-8(%sp), %sp		/* restore SP */ | 
 | 284 | 	ldd	-0x10(%sp), %rp		/* restore RP */ | 
 | 285 | 	bv	0(%rp) | 
 | 286 | 	nop | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 287 | ENDPROC(real64_call_asm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 |  | 
 | 289 | #endif | 
 | 290 |  | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 291 | 	.text | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 292 | 	/* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html | 
 | 293 | 	**	GCC 3.3 and later has a new function in libgcc.a for | 
 | 294 | 	**	comparing function pointers. | 
 | 295 | 	*/ | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 296 | ENTRY(__canonicalize_funcptr_for_compare) | 
| Grant Grundler | 413059f | 2005-10-21 22:46:48 -0400 | [diff] [blame] | 297 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 298 | 	bve (%r2) | 
 | 299 | #else | 
 | 300 | 	bv %r0(%r2) | 
 | 301 | #endif | 
 | 302 | 	copy %r26,%r28 | 
| Helge Deller | 8e9e984 | 2007-01-24 22:36:32 +0100 | [diff] [blame] | 303 | ENDPROC(__canonicalize_funcptr_for_compare) | 
 | 304 |  |