Commit | Line | Data |
---|---|---|
41c594ab RB |
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/stackframe.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 | /* | |
26 | The __smtc_ipi_vector would use k0 and k1 as temporaries and | |
27 | 1) Set EXL (this is per-VPE, so this can't be done by proxy!) | |
28 | 2) Restore the K/CU and IXMT bits to the pre "exception" state | |
29 | (EXL means no interrupts and access to the kernel map). | |
30 | 3) Set EPC to be the saved value of TCRestart. | |
31 | 4) Jump to the exception handler entry point passed by the sender. | |
32 | ||
33 | CAN 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 | |
51 | FEXPORT(__smtc_ipi_vector) | |
52 | .set noat | |
53 | /* Disable thread scheduling to make Status update atomic */ | |
54 | DMT 27 # dmt k1 | |
4277ff5e | 55 | _ehb |
41c594ab RB |
56 | /* Set EXL */ |
57 | mfc0 k0,CP0_STATUS | |
58 | ori k0,k0,ST0_EXL | |
59 | mtc0 k0,CP0_STATUS | |
4277ff5e | 60 | _ehb |
41c594ab RB |
61 | /* Thread scheduling now inhibited by EXL. Restore TE state. */ |
62 | andi k1,k1,VPECONTROL_TE | |
63 | beqz k1,1f | |
64 | emt | |
65 | 1: | |
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 | |
4277ff5e | 85 | _ehb |
41c594ab RB |
86 | get_saved_sp |
87 | /* Interrupting TC will have pre-set values in slots in the new frame */ | |
88 | 2: 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 | |
4277ff5e | 93 | _ehb |
41c594ab RB |
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 | |
192ef366 | 99 | TRACE_IRQS_OFF |
41c594ab RB |
100 | move a0,sp |
101 | /* Function to be invoked passed stack pad slot 5 */ | |
102 | lw t0,PT_PADSLOT5(sp) | |
103 | /* Argument from sender passed in stack pad slot 4 */ | |
104 | lw a1,PT_PADSLOT4(sp) | |
105 | jalr t0 | |
106 | nop | |
107 | j ret_from_irq | |
108 | nop | |
109 | ||
110 | /* | |
111 | * Called from idle loop to provoke processing of queued IPIs | |
112 | * First IPI message in queue passed as argument. | |
113 | */ | |
114 | ||
115 | LEAF(self_ipi) | |
116 | /* Before anything else, block interrupts */ | |
117 | mfc0 t0,CP0_TCSTATUS | |
118 | ori t1,t0,TCSTATUS_IXMT | |
119 | mtc0 t1,CP0_TCSTATUS | |
4277ff5e | 120 | _ehb |
41c594ab RB |
121 | /* We know we're in kernel mode, so prepare stack frame */ |
122 | subu t1,sp,PT_SIZE | |
123 | sw ra,PT_EPC(t1) | |
124 | sw a0,PT_PADSLOT4(t1) | |
125 | la t2,ipi_decode | |
126 | sw t2,PT_PADSLOT5(t1) | |
127 | /* Save pre-disable value of TCStatus */ | |
128 | sw t0,PT_TCSTATUS(t1) | |
129 | j __smtc_ipi_vector | |
130 | nop | |
131 | END(self_ipi) |