1/*
2 * Assembly Language Functions for MIPS MT SMTC support
3 */
4
5/*
6 * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */
7
8#include <asm/regdef.h>
9#include <asm/asmmacro.h>
10#include <asm/stackframe.h>
11#include <asm/irqflags.h>
12
13/*
14 * "Software Interrupt" linkage.
15 *
16 * This is invoked when an "Interrupt" is sent from one TC to another,
17 * where the TC to be interrupted is halted, has it's Restart address
18 * and Status values saved by the "remote control" thread, then modified
19 * to cause execution to begin here, in kenel mode. This code then
20 * disguises the TC state as that of an exception and transfers
21 * control to the general exception or vectored interrupt handler.
22 */
23	.set noreorder
24
25/*
26The __smtc_ipi_vector would use k0 and k1 as temporaries and
271) Set EXL (this is per-VPE, so this can't be done by proxy!)
282) Restore the K/CU and IXMT bits to the pre "exception" state
29   (EXL means no interrupts and access to the kernel map).
303) Set EPC to be the saved value of TCRestart.
314) Jump to the exception handler entry point passed by the sender.
32
33CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
34*/
35
36/*
37 * Reviled and slandered vision: Set EXL and restore K/CU/IXMT
38 * state of pre-halt thread, then save everything and call
39 * thought some function pointer to imaginary_exception, which
40 * will parse a register value or memory message queue to
41 * deliver things like interprocessor interrupts. On return
42 * from that function, jump to the global ret_from_irq code
43 * to invoke the scheduler and return as appropriate.
44 */
45
46#define PT_PADSLOT4 (PT_R0-8)
47#define PT_PADSLOT5 (PT_R0-4)
48
49	.text
50	.align 5
51FEXPORT(__smtc_ipi_vector)
52	.set	noat
53	/* Disable thread scheduling to make Status update atomic */
54	DMT	27					# dmt	k1
55	_ehb
56	/* Set EXL */
57	mfc0	k0,CP0_STATUS
58	ori	k0,k0,ST0_EXL
59	mtc0	k0,CP0_STATUS
60	_ehb
61	/* Thread scheduling now inhibited by EXL. Restore TE state. */
62	andi	k1,k1,VPECONTROL_TE
63	beqz	k1,1f
64	emt
651:
66	/*
67	 * The IPI sender has put some information on the anticipated
68	 * kernel stack frame.  If we were in user mode, this will be
69	 * built above the saved kernel SP.  If we were already in the
70	 * kernel, it will be built above the current CPU SP.
71	 *
72	 * Were we in kernel mode, as indicated by CU0?
73	 */
74	sll	k1,k0,3
75	.set noreorder
76	bltz	k1,2f
77	move	k1,sp
78	.set reorder
79	/*
80	 * If previously in user mode, set CU0 and use kernel stack.
81	 */
82	li	k1,ST0_CU0
83	or	k1,k1,k0
84	mtc0	k1,CP0_STATUS
85	_ehb
86	get_saved_sp
87	/* Interrupting TC will have pre-set values in slots in the new frame */
882:	subu	k1,k1,PT_SIZE
89	/* Load TCStatus Value */
90	lw	k0,PT_TCSTATUS(k1)
91	/* Write it to TCStatus to restore CU/KSU/IXMT state */
92	mtc0	k0,$2,1
93	_ehb
94	lw	k0,PT_EPC(k1)
95	mtc0	k0,CP0_EPC
96	/* Save all will redundantly recompute the SP, but use it for now */
97	SAVE_ALL
98	CLI
99	TRACE_IRQS_OFF
100	/* Function to be invoked passed stack pad slot 5 */
101	lw	t0,PT_PADSLOT5(sp)
102	/* Argument from sender passed in stack pad slot 4 */
103	lw	a0,PT_PADSLOT4(sp)
104	LONG_L	s0, TI_REGS($28)
105	LONG_S	sp, TI_REGS($28)
106	PTR_LA	ra, ret_from_irq
107	jr	t0
108
109/*
110 * Called from idle loop to provoke processing of queued IPIs
111 * First IPI message in queue passed as argument.
112 */
113
114LEAF(self_ipi)
115	/* Before anything else, block interrupts */
116	mfc0	t0,CP0_TCSTATUS
117	ori	t1,t0,TCSTATUS_IXMT
118	mtc0	t1,CP0_TCSTATUS
119	_ehb
120	/* We know we're in kernel mode, so prepare stack frame */
121	subu	t1,sp,PT_SIZE
122	sw	ra,PT_EPC(t1)
123	sw	a0,PT_PADSLOT4(t1)
124	la	t2,ipi_decode
125	sw	t2,PT_PADSLOT5(t1)
126	/* Save pre-disable value of TCStatus */
127	sw	t0,PT_TCSTATUS(t1)
128	j	__smtc_ipi_vector
129	nop
130END(self_ipi)
131