| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Assembly Language Functions for MIPS MT SMTC support | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/regdef.h> | 
					
						
							|  |  |  | #include <asm/asmmacro.h> | 
					
						
							|  |  |  | #include <asm/stackframe.h> | 
					
						
							| 
									
										
										
										
											2006-08-16 14:05:11 +01:00
										 |  |  | #include <asm/irqflags.h> | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * "Software Interrupt" linkage. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is invoked when an "Interrupt" is sent from one TC to another, | 
					
						
							|  |  |  |  * where the TC to be interrupted is halted, has it's Restart address | 
					
						
							|  |  |  |  * and Status values saved by the "remote control" thread, then modified | 
					
						
							|  |  |  |  * to cause execution to begin here, in kenel mode. This code then | 
					
						
							|  |  |  |  * disguises the TC state as that of an exception and transfers | 
					
						
							|  |  |  |  * control to the general exception or vectored interrupt handler. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.set noreorder
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | The __smtc_ipi_vector would use k0 and k1 as temporaries and | 
					
						
							|  |  |  | 1) Set EXL (this is per-VPE, so this can't be done by proxy!) | 
					
						
							|  |  |  | 2) Restore the K/CU and IXMT bits to the pre "exception" state | 
					
						
							|  |  |  |    (EXL means no interrupts and access to the kernel map). | 
					
						
							|  |  |  | 3) Set EPC to be the saved value of TCRestart. | 
					
						
							|  |  |  | 4) Jump to the exception handler entry point passed by the sender. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED?? | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Reviled and slandered vision: Set EXL and restore K/CU/IXMT | 
					
						
							|  |  |  |  * state of pre-halt thread, then save everything and call | 
					
						
							|  |  |  |  * thought some function pointer to imaginary_exception, which | 
					
						
							|  |  |  |  * will parse a register value or memory message queue to | 
					
						
							|  |  |  |  * deliver things like interprocessor interrupts. On return | 
					
						
							|  |  |  |  * from that function, jump to the global ret_from_irq code | 
					
						
							|  |  |  |  * to invoke the scheduler and return as appropriate. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PT_PADSLOT4 (PT_R0-8) | 
					
						
							|  |  |  | #define PT_PADSLOT5 (PT_R0-4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.text | 
					
						
							|  |  |  | 	.align 5
 | 
					
						
							|  |  |  | FEXPORT(__smtc_ipi_vector) | 
					
						
							| 
									
										
										
										
											2013-03-25 12:15:55 -05:00
										 |  |  | #ifdef CONFIG_CPU_MICROMIPS | 
					
						
							|  |  |  | 	nop | 
					
						
							|  |  |  | #endif | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	.set	noat
 | 
					
						
							|  |  |  | 	/* Disable thread scheduling to make Status update atomic */ | 
					
						
							|  |  |  | 	DMT	27					# dmt	k1 | 
					
						
							| 
									
										
										
										
											2006-06-03 22:40:15 +01:00
										 |  |  | 	_ehb | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	/* Set EXL */ | 
					
						
							|  |  |  | 	mfc0	k0,CP0_STATUS | 
					
						
							|  |  |  | 	ori	k0,k0,ST0_EXL | 
					
						
							|  |  |  | 	mtc0	k0,CP0_STATUS | 
					
						
							| 
									
										
										
										
											2006-06-03 22:40:15 +01:00
										 |  |  | 	_ehb | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	/* Thread scheduling now inhibited by EXL. Restore TE state. */ | 
					
						
							|  |  |  | 	andi	k1,k1,VPECONTROL_TE | 
					
						
							|  |  |  | 	beqz	k1,1f | 
					
						
							|  |  |  | 	emt | 
					
						
							|  |  |  | 1: | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * The IPI sender has put some information on the anticipated | 
					
						
							| 
									
										
										
										
											2013-01-22 12:59:30 +01:00
										 |  |  | 	 * kernel stack frame.	If we were in user mode, this will be | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	 * built above the saved kernel SP.  If we were already in the | 
					
						
							|  |  |  | 	 * kernel, it will be built above the current CPU SP. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Were we in kernel mode, as indicated by CU0? | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	sll	k1,k0,3 | 
					
						
							|  |  |  | 	.set noreorder
 | 
					
						
							|  |  |  | 	bltz	k1,2f | 
					
						
							|  |  |  | 	move	k1,sp | 
					
						
							|  |  |  | 	.set reorder
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * If previously in user mode, set CU0 and use kernel stack. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	li	k1,ST0_CU0 | 
					
						
							|  |  |  | 	or	k1,k1,k0 | 
					
						
							|  |  |  | 	mtc0	k1,CP0_STATUS | 
					
						
							| 
									
										
										
										
											2006-06-03 22:40:15 +01:00
										 |  |  | 	_ehb | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	get_saved_sp | 
					
						
							|  |  |  | 	/* Interrupting TC will have pre-set values in slots in the new frame */ | 
					
						
							|  |  |  | 2:	subu	k1,k1,PT_SIZE | 
					
						
							|  |  |  | 	/* Load TCStatus Value */ | 
					
						
							|  |  |  | 	lw	k0,PT_TCSTATUS(k1) | 
					
						
							|  |  |  | 	/* Write it to TCStatus to restore CU/KSU/IXMT state */ | 
					
						
							|  |  |  | 	mtc0	k0,$2,1 | 
					
						
							| 
									
										
										
										
											2006-06-03 22:40:15 +01:00
										 |  |  | 	_ehb | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	lw	k0,PT_EPC(k1) | 
					
						
							|  |  |  | 	mtc0	k0,CP0_EPC | 
					
						
							|  |  |  | 	/* Save all will redundantly recompute the SP, but use it for now */ | 
					
						
							|  |  |  | 	SAVE_ALL | 
					
						
							|  |  |  | 	CLI | 
					
						
							| 
									
										
										
										
											2006-07-07 14:07:18 +01:00
										 |  |  | 	TRACE_IRQS_OFF | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	/* Function to be invoked passed stack pad slot 5 */ | 
					
						
							|  |  |  | 	lw	t0,PT_PADSLOT5(sp) | 
					
						
							|  |  |  | 	/* Argument from sender passed in stack pad slot 4 */ | 
					
						
							| 
									
										
										
										
											2006-10-09 01:24:23 +09:00
										 |  |  | 	lw	a0,PT_PADSLOT4(sp) | 
					
						
							| 
									
										
										
										
											2006-10-31 22:49:04 +00:00
										 |  |  | 	LONG_L	s0, TI_REGS($28) | 
					
						
							|  |  |  | 	LONG_S	sp, TI_REGS($28) | 
					
						
							|  |  |  | 	PTR_LA	ra, ret_from_irq | 
					
						
							| 
									
										
										
										
											2006-10-09 01:24:23 +09:00
										 |  |  | 	jr	t0 | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  * Called from idle loop to provoke processing of queued IPIs | 
					
						
							|  |  |  |  * First IPI message in queue passed as argument. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LEAF(self_ipi) | 
					
						
							|  |  |  | 	/* Before anything else, block interrupts */ | 
					
						
							|  |  |  | 	mfc0	t0,CP0_TCSTATUS | 
					
						
							|  |  |  | 	ori	t1,t0,TCSTATUS_IXMT | 
					
						
							|  |  |  | 	mtc0	t1,CP0_TCSTATUS | 
					
						
							| 
									
										
										
										
											2006-06-03 22:40:15 +01:00
										 |  |  | 	_ehb | 
					
						
							| 
									
										
										
										
											2006-04-05 09:45:45 +01:00
										 |  |  | 	/* We know we're in kernel mode, so prepare stack frame */ | 
					
						
							|  |  |  | 	subu	t1,sp,PT_SIZE | 
					
						
							|  |  |  | 	sw	ra,PT_EPC(t1) | 
					
						
							|  |  |  | 	sw	a0,PT_PADSLOT4(t1) | 
					
						
							|  |  |  | 	la	t2,ipi_decode | 
					
						
							|  |  |  | 	sw	t2,PT_PADSLOT5(t1) | 
					
						
							|  |  |  | 	/* Save pre-disable value of TCStatus */ | 
					
						
							|  |  |  | 	sw	t0,PT_TCSTATUS(t1) | 
					
						
							|  |  |  | 	j	__smtc_ipi_vector | 
					
						
							|  |  |  | 	nop | 
					
						
							|  |  |  | END(self_ipi) |