1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * ARCv2 ISA based core Low Level Intr/Traps/Exceptions(non-TLB) Handling |
4 | * |
5 | * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) |
6 | */ |
7 | |
8 | #include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */ |
9 | #include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */ |
10 | #include <asm/errno.h> |
11 | #include <asm/arcregs.h> |
12 | #include <asm/irqflags.h> |
13 | #include <asm/mmu.h> |
14 | |
15 | ; A maximum number of supported interrupts in the core interrupt controller. |
16 | ; This number is not equal to the maximum interrupt number (256) because |
17 | ; first 16 lines are reserved for exceptions and are not configurable. |
18 | #define NR_CPU_IRQS 240 |
19 | |
20 | .cpu HS |
21 | |
22 | #define VECTOR .word |
23 | |
24 | ;############################ Vector Table ################################# |
25 | |
26 | .section .vector,"a" ,@progbits |
27 | .align 4 |
28 | |
29 | # Initial 16 slots are Exception Vectors |
30 | VECTOR res_service ; Reset Vector |
31 | VECTOR mem_service ; Mem exception |
32 | VECTOR instr_service ; Instrn Error |
33 | VECTOR EV_MachineCheck ; Fatal Machine check |
34 | VECTOR EV_TLBMissI ; Intruction TLB miss |
35 | VECTOR EV_TLBMissD ; Data TLB miss |
36 | VECTOR EV_TLBProtV ; Protection Violation |
37 | VECTOR EV_PrivilegeV ; Privilege Violation |
38 | VECTOR EV_SWI ; Software Breakpoint |
39 | VECTOR EV_Trap ; Trap exception |
40 | VECTOR EV_Extension ; Extn Instruction Exception |
41 | VECTOR EV_DivZero ; Divide by Zero |
42 | VECTOR EV_DCError ; Data Cache Error |
43 | VECTOR EV_Misaligned ; Misaligned Data Access |
44 | VECTOR reserved ; Reserved slots |
45 | VECTOR reserved ; Reserved slots |
46 | |
47 | # Begin Interrupt Vectors |
48 | VECTOR handle_interrupt ; (16) Timer0 |
49 | VECTOR handle_interrupt ; unused (Timer1) |
50 | VECTOR handle_interrupt ; unused (WDT) |
51 | VECTOR handle_interrupt ; (19) Inter core Interrupt (IPI) |
52 | VECTOR handle_interrupt ; (20) perf Interrupt |
53 | VECTOR handle_interrupt ; (21) Software Triggered Intr (Self IPI) |
54 | VECTOR handle_interrupt ; unused |
55 | VECTOR handle_interrupt ; (23) unused |
56 | # End of fixed IRQs |
57 | |
58 | .rept NR_CPU_IRQS - 8 |
59 | VECTOR handle_interrupt |
60 | .endr |
61 | |
62 | .section .text, "ax" ,@progbits |
63 | |
64 | reserved: |
65 | flag 1 ; Unexpected event, halt |
66 | |
67 | ;##################### Interrupt Handling ############################## |
68 | |
69 | ENTRY(handle_interrupt) |
70 | |
71 | INTERRUPT_PROLOGUE |
72 | |
73 | # irq control APIs local_irq_save/restore/disable/enable fiddle with |
74 | # global interrupt enable bits in STATUS32 (.IE for 1 prio, .E[] for 2 prio) |
75 | # However a taken interrupt doesn't clear these bits. Thus irqs_disabled() |
76 | # query in hard ISR path would return false (since .IE is set) which would |
77 | # trips genirq interrupt handling asserts. |
78 | # |
79 | # So do a "soft" disable of interrutps here. |
80 | # |
81 | # Note this disable is only for consistent book-keeping as further interrupts |
82 | # will be disabled anyways even w/o this. Hardware tracks active interrupts |
83 | # seperately in AUX_IRQ_ACT.active and will not take new interrupts |
84 | # unless this one returns (or higher prio becomes pending in 2-prio scheme) |
85 | |
86 | IRQ_DISABLE |
87 | |
88 | ; icause is banked: one per priority level |
89 | ; so a higher prio interrupt taken here won't clobber prev prio icause |
90 | lr r0, [ICAUSE] |
91 | mov blink, ret_from_exception |
92 | |
93 | b.d arch_do_IRQ |
94 | mov r1, sp |
95 | |
96 | END(handle_interrupt) |
97 | |
98 | ;################### Non TLB Exception Handling ############################# |
99 | |
100 | ENTRY(EV_SWI) |
101 | ; TODO: implement this |
102 | EXCEPTION_PROLOGUE |
103 | b ret_from_exception |
104 | END(EV_SWI) |
105 | |
106 | ENTRY(EV_DivZero) |
107 | ; TODO: implement this |
108 | EXCEPTION_PROLOGUE |
109 | b ret_from_exception |
110 | END(EV_DivZero) |
111 | |
112 | ENTRY(EV_DCError) |
113 | ; TODO: implement this |
114 | EXCEPTION_PROLOGUE |
115 | b ret_from_exception |
116 | END(EV_DCError) |
117 | |
118 | ; --------------------------------------------- |
119 | ; Memory Error Exception Handler |
120 | ; - Unlike ARCompact, handles Bus errors for both User/Kernel mode, |
121 | ; Instruction fetch or Data access, under a single Exception Vector |
122 | ; --------------------------------------------- |
123 | |
124 | ENTRY(mem_service) |
125 | |
126 | EXCEPTION_PROLOGUE |
127 | |
128 | bl do_memory_error |
129 | b ret_from_exception |
130 | END(mem_service) |
131 | |
132 | ENTRY(EV_Misaligned) |
133 | |
134 | EXCEPTION_PROLOGUE |
135 | |
136 | SAVE_CALLEE_SAVED_USER |
137 | mov r2, sp ; callee_regs |
138 | |
139 | bl do_misaligned_access |
140 | |
141 | ; TBD: optimize - do this only if a callee reg was involved |
142 | ; either a dst of emulated LD/ST or src with address-writeback |
143 | RESTORE_CALLEE_SAVED_USER |
144 | |
145 | b ret_from_exception |
146 | END(EV_Misaligned) |
147 | |
148 | ; --------------------------------------------- |
149 | ; Protection Violation Exception Handler |
150 | ; --------------------------------------------- |
151 | |
152 | ENTRY(EV_TLBProtV) |
153 | |
154 | EXCEPTION_PROLOGUE |
155 | |
156 | mov blink, ret_from_exception |
157 | b do_page_fault |
158 | |
159 | END(EV_TLBProtV) |
160 | |
161 | ; From Linux standpoint Slow Path I/D TLB Miss is same a ProtV as they |
162 | ; need to call do_page_fault(). |
163 | ; ECR in pt_regs provides whether access was R/W/X |
164 | |
165 | .global call_do_page_fault |
166 | .set call_do_page_fault, EV_TLBProtV |
167 | |
168 | ;############# Common Handlers for ARCompact and ARCv2 ############## |
169 | |
170 | #include "entry.S" |
171 | |
172 | ;############# Return from Intr/Excp/Trap (ARCv2 ISA Specifics) ############## |
173 | ; |
174 | ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap) |
175 | ; IRQ shd definitely not happen between now and rtie |
176 | ; All 2 entry points to here already disable interrupts |
177 | |
178 | .Lrestore_regs: |
179 | restore_regs: |
180 | |
181 | # Interrpts are actually disabled from this point on, but will get |
182 | # reenabled after we return from interrupt/exception. |
183 | # But irq tracer needs to be told now... |
184 | TRACE_ASM_IRQ_ENABLE |
185 | |
186 | ld r0, [sp, PT_status32] ; U/K mode at time of entry |
187 | lr r10, [AUX_IRQ_ACT] |
188 | |
189 | bmsk r11, r10, 15 ; extract AUX_IRQ_ACT.active |
190 | breq r11, 0, .Lexcept_ret ; No intr active, ret from Exception |
191 | |
192 | ;####### Return from Intr ####### |
193 | |
194 | .Lisr_ret: |
195 | |
196 | debug_marker_l1: |
197 | ; bbit1.nt r0, STATUS_DE_BIT, .Lintr_ret_to_delay_slot |
198 | btst r0, STATUS_DE_BIT ; Z flag set if bit clear |
199 | bnz .Lintr_ret_to_delay_slot ; branch if STATUS_DE_BIT set |
200 | |
201 | ; Handle special case #1: (Entry via Exception, Return via IRQ) |
202 | ; |
203 | ; Exception in U mode, preempted in kernel, Intr taken (K mode), orig |
204 | ; task now returning to U mode (riding the Intr) |
205 | ; AUX_IRQ_ACTIVE won't have U bit set (since intr in K mode), hence SP |
206 | ; won't be switched to correct U mode value (from AUX_SP) |
207 | ; So force AUX_IRQ_ACT.U for such a case |
208 | |
209 | btst r0, STATUS_U_BIT ; Z flag set if K (Z clear for U) |
210 | bset.nz r11, r11, AUX_IRQ_ACT_BIT_U ; NZ means U |
211 | sr r11, [AUX_IRQ_ACT] |
212 | |
213 | INTERRUPT_EPILOGUE |
214 | rtie |
215 | |
216 | ;####### Return from Exception / pure kernel mode ####### |
217 | |
218 | .Lexcept_ret: ; Expects r0 has PT_status32 |
219 | |
220 | debug_marker_syscall: |
221 | EXCEPTION_EPILOGUE |
222 | rtie |
223 | |
224 | ;####### Return from Intr to insn in delay slot ####### |
225 | |
226 | ; Handle special case #2: (Entry via Exception in Delay Slot, Return via IRQ) |
227 | ; |
228 | ; Intr returning to a Delay Slot (DS) insn |
229 | ; (since IRQ NOT allowed in DS in ARCv2, this can only happen if orig |
230 | ; entry was via Exception in DS which got preempted in kernel). |
231 | ; |
232 | ; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround |
233 | ; |
234 | ; Solution is to drop out of interrupt context into pure kernel mode |
235 | ; and return from pure kernel mode which does right things for delay slot |
236 | |
237 | .Lintr_ret_to_delay_slot: |
238 | debug_marker_ds: |
239 | |
240 | ld r2, [@intr_to_DE_cnt] |
241 | add r2, r2, 1 |
242 | st r2, [@intr_to_DE_cnt] |
243 | |
244 | ; drop out of interrupt context (clear AUX_IRQ_ACT.active) |
245 | bmskn r11, r10, 15 |
246 | sr r11, [AUX_IRQ_ACT] |
247 | b .Lexcept_ret |
248 | |
249 | END(ret_from_exception) |
250 | |