Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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> |
Ralf Baechle | 6e74bae | 2006-08-16 14:05:11 +0100 | [diff] [blame] | 11 | #include <asm/irqflags.h> |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 |
Ralf Baechle | 4277ff5 | 2006-06-03 22:40:15 +0100 | [diff] [blame] | 55 | _ehb |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 56 | /* Set EXL */ |
| 57 | mfc0 k0,CP0_STATUS |
| 58 | ori k0,k0,ST0_EXL |
| 59 | mtc0 k0,CP0_STATUS |
Ralf Baechle | 4277ff5 | 2006-06-03 22:40:15 +0100 | [diff] [blame] | 60 | _ehb |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 |
Ralf Baechle | 4277ff5 | 2006-06-03 22:40:15 +0100 | [diff] [blame] | 85 | _ehb |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 |
Ralf Baechle | 4277ff5 | 2006-06-03 22:40:15 +0100 | [diff] [blame] | 93 | _ehb |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 |
Ralf Baechle | 192ef36 | 2006-07-07 14:07:18 +0100 | [diff] [blame] | 99 | TRACE_IRQS_OFF |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 */ |
Atsushi Nemoto | f431baa | 2006-10-09 01:24:23 +0900 | [diff] [blame] | 103 | lw a0,PT_PADSLOT4(sp) |
Ralf Baechle | cb56837 | 2006-10-31 22:49:04 +0000 | [diff] [blame] | 104 | LONG_L s0, TI_REGS($28) |
| 105 | LONG_S sp, TI_REGS($28) |
| 106 | PTR_LA ra, ret_from_irq |
Atsushi Nemoto | f431baa | 2006-10-09 01:24:23 +0900 | [diff] [blame] | 107 | jr t0 |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 108 | |
| 109 | /* |
| 110 | * Called from idle loop to provoke processing of queued IPIs |
| 111 | * First IPI message in queue passed as argument. |
| 112 | */ |
| 113 | |
| 114 | LEAF(self_ipi) |
| 115 | /* Before anything else, block interrupts */ |
| 116 | mfc0 t0,CP0_TCSTATUS |
| 117 | ori t1,t0,TCSTATUS_IXMT |
| 118 | mtc0 t1,CP0_TCSTATUS |
Ralf Baechle | 4277ff5 | 2006-06-03 22:40:15 +0100 | [diff] [blame] | 119 | _ehb |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 |
Ralf Baechle | 41c594a | 2006-04-05 09:45:45 +0100 | [diff] [blame] | 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 |
| 130 | END(self_ipi) |