1 1.21 rin /* $NetBSD: sa11x0_irq.S,v 1.21 2021/11/08 23:57:23 rin Exp $ */ 2 1.1 rjs 3 1.1 rjs /* 4 1.1 rjs * Copyright (c) 1998 Mark Brinicombe. 5 1.1 rjs * Copyright (c) 1998 Causality Limited 6 1.1 rjs * All rights reserved. 7 1.1 rjs * 8 1.1 rjs * This code is derived from software contributed to the NetBSD Foundation 9 1.1 rjs * by IWAMOTO Toshihiro. 10 1.1 rjs * 11 1.1 rjs * Redistribution and use in source and binary forms, with or without 12 1.1 rjs * modification, are permitted provided that the following conditions 13 1.1 rjs * are met: 14 1.1 rjs * 1. Redistributions of source code must retain the above copyright 15 1.1 rjs * notice, this list of conditions and the following disclaimer. 16 1.1 rjs * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 rjs * notice, this list of conditions and the following disclaimer in the 18 1.1 rjs * documentation and/or other materials provided with the distribution. 19 1.1 rjs * 3. All advertising materials mentioning features or use of this software 20 1.1 rjs * must display the following acknowledgement: 21 1.1 rjs * This product includes software developed by Mark Brinicombe 22 1.1 rjs * for the NetBSD Project. 23 1.1 rjs * 4. The name of the company nor the name of the author may be used to 24 1.1 rjs * endorse or promote products derived from this software without specific 25 1.1 rjs * prior written permission. 26 1.1 rjs * 27 1.1 rjs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 28 1.1 rjs * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 29 1.1 rjs * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 1.1 rjs * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 31 1.1 rjs * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 32 1.1 rjs * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 1.1 rjs * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 1.1 rjs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 1.1 rjs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 1.1 rjs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 1.1 rjs * SUCH DAMAGE. 38 1.1 rjs */ 39 1.1 rjs 40 1.1 rjs #include "opt_irqstats.h" 41 1.1 rjs 42 1.1 rjs #include "assym.h" 43 1.17 matt 44 1.17 matt #include <arm/asm.h> 45 1.17 matt #include <arm/locore.h> 46 1.3 ichiro #include <arm/sa11x0/sa11x0_reg.h> 47 1.1 rjs 48 1.1 rjs 49 1.1 rjs .text 50 1.1 rjs .align 0 51 1.1 rjs 52 1.1 rjs Lspl_masks: 53 1.1 rjs .word _C_LABEL(spl_masks) 54 1.1 rjs 55 1.14 rafal Lcpu_info_store: 56 1.14 rafal .word _C_LABEL(cpu_info_store) 57 1.14 rafal 58 1.1 rjs .globl _C_LABEL(saipic_base) 59 1.1 rjs _C_LABEL(saipic_base): 60 1.1 rjs .word 0x00000000 61 1.1 rjs 62 1.1 rjs #ifdef INTR_DEBUG 63 1.1 rjs Ldbg_str: 64 1.1 rjs .asciz "irq_entry %x %x\n" 65 1.14 rafal .align 5 66 1.1 rjs #endif 67 1.1 rjs 68 1.10 thorpej LOCK_CAS_CHECK_LOCALS 69 1.10 thorpej 70 1.6 scw AST_ALIGNMENT_FAULT_LOCALS 71 1.6 scw 72 1.1 rjs /* 73 1.7 peter * Register usage 74 1.1 rjs * 75 1.20 skrll * r4 - Pointer to curcpu 76 1.20 skrll * r5 - pointer to curlwp 77 1.1 rjs * r6 - Address of current handler 78 1.16 matt * r7 - pspr mode 79 1.1 rjs * r8 - Current IRQ requests. 80 1.1 rjs * r9 - Used to count through possible IRQ bits. 81 1.21 rin * r10 - Pointer to handler pointer list 82 1.1 rjs */ 83 1.1 rjs 84 1.1 rjs ASENTRY_NP(irq_entry) 85 1.1 rjs sub lr, lr, #0x00000004 /* Adjust the lr */ 86 1.1 rjs 87 1.1 rjs PUSHFRAMEINSVC /* Push an interrupt frame */ 88 1.20 skrll ENABLE_ALIGNMENT_FAULTS /* puts cur{cpu,lwp} in r4/r5 */ 89 1.1 rjs 90 1.1 rjs /* Load r8 with the SAIPIC interrupt requests */ 91 1.1 rjs 92 1.21 rin ldr r8, _C_LABEL(saipic_base) 93 1.21 rin ldr r8, [r8, #(SAIPIC_IP)] /* Load IRQ pending register */ 94 1.1 rjs 95 1.1 rjs #ifdef INTR_DEBUG 96 1.4 bjh21 adr r0, Ldbg_str 97 1.1 rjs mov r1, r8 98 1.21 rin ldr r2, _C_LABEL(saipic_base) 99 1.21 rin ldr r2, [r2, #(SAIPIC_MR)] 100 1.1 rjs bl _C_LABEL(printf) 101 1.1 rjs #endif 102 1.1 rjs /* 103 1.1 rjs * Note that we have entered the IRQ handler. 104 1.1 rjs * We are in SVC mode so we cannot use the processor mode 105 1.1 rjs * to determine if we are in an IRQ. Instead we will count the 106 1.1 rjs * each time the interrupt handler is nested. 107 1.1 rjs */ 108 1.1 rjs 109 1.13 matt ldr r1, [r4, #CI_INTR_DEPTH] 110 1.1 rjs add r1, r1, #1 111 1.13 matt str r1, [r4, #CI_INTR_DEPTH] 112 1.1 rjs 113 1.1 rjs /* 114 1.1 rjs * Need to block all interrupts at the IPL or lower for 115 1.1 rjs * all asserted interrupts. 116 1.1 rjs * This basically emulates hardware interrupt priority levels. 117 1.1 rjs * Means we need to go through the interrupt mask and for 118 1.1 rjs * every asserted interrupt we need to mask out all other 119 1.1 rjs * interrupts at the same or lower IPL. 120 1.1 rjs * If only we could wait until the main loop but we need to sort 121 1.1 rjs * this out first so interrupts can be re-enabled. 122 1.1 rjs * 123 1.1 rjs * This would benefit from a special ffs type routine 124 1.1 rjs */ 125 1.1 rjs 126 1.13 matt mov r9, #(NIPL - 1) 127 1.21 rin ldr r10, Lspl_masks 128 1.1 rjs 129 1.1 rjs Lfind_highest_ipl: 130 1.21 rin ldr r2, [r10, r9, lsl #2] 131 1.1 rjs tst r8, r2 132 1.1 rjs subeq r9, r9, #1 133 1.1 rjs beq Lfind_highest_ipl 134 1.1 rjs 135 1.1 rjs /* r9 = SPL level of highest priority interrupt */ 136 1.1 rjs add r9, r9, #1 137 1.21 rin ldr r2, [r10, r9, lsl #2] 138 1.1 rjs 139 1.13 matt ldr r1, [r4, #CI_CPL] 140 1.13 matt str r9, [r4, #CI_CPL] 141 1.1 rjs stmfd sp!, {r1} 142 1.1 rjs 143 1.1 rjs /* Update the SAIP irq masks */ 144 1.1 rjs bl _C_LABEL(irq_setmasks) 145 1.1 rjs 146 1.1 rjs #ifdef INTR_DEBUG 147 1.1 rjs stmfd sp!, {r0,r1,r2} 148 1.4 bjh21 adr r0, Ldbg_str 149 1.1 rjs mov r1, #1 150 1.1 rjs mov r2, r9 151 1.1 rjs bl _C_LABEL(printf) 152 1.1 rjs ldmia sp!, {r0,r1,r2} 153 1.1 rjs #endif 154 1.18 joerg mrs r0, cpsr /* Enable IRQs */ 155 1.1 rjs bic r0, r0, #I32_bit 156 1.1 rjs msr cpsr_all, r0 157 1.1 rjs 158 1.21 rin ldr r10, Lirqhandlers 159 1.1 rjs mov r9, #0x00000001 160 1.1 rjs 161 1.1 rjs irqloop: 162 1.1 rjs /* This would benefit from a special ffs type routine */ 163 1.1 rjs tst r8, r9 /* Is a bit set ? */ 164 1.1 rjs beq nextirq /* No ? try next bit */ 165 1.1 rjs 166 1.21 rin ldr r6, [r10] /* Get address of first handler structure */ 167 1.1 rjs 168 1.1 rjs teq r6, #0x00000000 /* Do we have a handler */ 169 1.1 rjs moveq r0, r8 /* IRQ requests as arg 0 */ 170 1.1 rjs beq _C_LABEL(stray_irqhandler) /* call special handler */ 171 1.1 rjs 172 1.15 matt ldr r0, [r4, #(CI_CC_NINTR)] 173 1.15 matt ldr r1, [r4, #(CI_CC_NINTR+4)] 174 1.15 matt #ifdef _ARMEL 175 1.15 matt adds r0, r0, #0x00000001 176 1.15 matt adc r1, r1, #0x00000001 177 1.15 matt #else 178 1.15 matt adds r1, r1, #0x00000001 179 1.15 matt adc r0, r0, #0x00000000 180 1.15 matt #endif 181 1.15 matt str r0, [r4, #(CI_CC_NINTR)] 182 1.15 matt str r1, [r4, #(CI_CC_NINTR+4)] 183 1.1 rjs 184 1.1 rjs /* 185 1.7 peter * XXX: Should stats be accumulated for every interrupt routine 186 1.1 rjs * called or for every physical interrupt that is serviced. 187 1.1 rjs */ 188 1.1 rjs 189 1.1 rjs #ifdef IRQSTATS 190 1.1 rjs ldr r0, Lintrcnt 191 1.1 rjs ldr r1, [r6, #(IH_COUNT)] 192 1.1 rjs 193 1.1 rjs add r0, r0, r1, lsl #2 194 1.1 rjs ldr r1, [r0] 195 1.1 rjs add r1, r1, #0x00000001 196 1.1 rjs str r1, [r0] 197 1.1 rjs #endif /* IRQSTATS */ 198 1.1 rjs 199 1.1 rjs irqchainloop: 200 1.1 rjs #ifdef INTR_DEBUG 201 1.1 rjs stmfd sp!, {r0,r1,r2} 202 1.4 bjh21 adr r0, Ldbg_str 203 1.1 rjs mov r1, #2 204 1.1 rjs bl _C_LABEL(printf) 205 1.1 rjs ldmia sp!, {r0,r1,r2} 206 1.1 rjs #endif 207 1.1 rjs ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 208 1.1 rjs teq r0, #0x00000000 /* If arg is zero pass stack frame */ 209 1.1 rjs addeq r0, sp, #4 /* ... stack frame [XXX needs care] */ 210 1.4 bjh21 mov lr, pc /* return address */ 211 1.1 rjs ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 212 1.1 rjs 213 1.1 rjs teq r0, #0x00000001 /* Was the irq serviced ? */ 214 1.1 rjs beq irqdone 215 1.1 rjs 216 1.1 rjs ldr r6, [r6, #(IH_NEXT)] 217 1.1 rjs teq r6, #0x00000000 218 1.1 rjs bne irqchainloop 219 1.1 rjs 220 1.1 rjs irqdone: 221 1.1 rjs nextirq: 222 1.21 rin add r10, r10, #0x00000004 /* update pointer to handlers */ 223 1.1 rjs mov r9, r9, lsl #1 /* move on to next bit */ 224 1.1 rjs teq r9, #(1 << 31) /* done the last bit ? */ 225 1.1 rjs bne irqloop /* no - loop back. */ 226 1.1 rjs 227 1.1 rjs ldmfd sp!, {r2} 228 1.13 matt str r2, [r4, #CI_CPL] 229 1.1 rjs 230 1.1 rjs /* Restore previous disabled mask */ 231 1.1 rjs bl _C_LABEL(irq_setmasks) 232 1.1 rjs 233 1.1 rjs /* Kill IRQ's in preparation for exit */ 234 1.18 joerg mrs r0, cpsr 235 1.1 rjs orr r0, r0, #(I32_bit) 236 1.1 rjs msr cpsr_all, r0 237 1.1 rjs 238 1.1 rjs #ifdef INTR_DEBUG 239 1.9 peter adr r0, Ldbg_str 240 1.1 rjs mov r1, #3 241 1.21 rin ldr r2, _C_LABEL(saipic_base) 242 1.21 rin ldr r2, [r2, #(SAIPIC_MR)] 243 1.1 rjs bl _C_LABEL(printf) 244 1.1 rjs #endif 245 1.1 rjs 246 1.1 rjs /* Decrement the nest count */ 247 1.13 matt ldr r1, [r4, #CI_INTR_DEPTH] 248 1.1 rjs sub r1, r1, #1 249 1.13 matt str r1, [r4, #CI_INTR_DEPTH] 250 1.1 rjs 251 1.10 thorpej LOCK_CAS_CHECK 252 1.10 thorpej 253 1.6 scw DO_AST_AND_RESTORE_ALIGNMENT_FAULTS 254 1.1 rjs PULLFRAMEFROMSVCANDEXIT 255 1.1 rjs 256 1.1 rjs /* NOT REACHED */ 257 1.1 rjs b . - 8 258 1.1 rjs 259 1.1 rjs ENTRY(irq_setmasks) 260 1.14 rafal stmfd sp!, {r0, r1, r4, lr} /* Preserve registers */ 261 1.14 rafal 262 1.1 rjs /* Disable interrupts */ 263 1.18 joerg mrs r1, cpsr 264 1.14 rafal orr r3, r1, #(I32_bit) 265 1.14 rafal msr cpsr_all, r3 266 1.1 rjs 267 1.1 rjs /* Calculate interrupt mask */ 268 1.1 rjs ldr r0, Lspl_masks 269 1.14 rafal ldr r4, Lcpu_info_store 270 1.13 matt ldr r2, [r4, #CI_CPL] 271 1.1 rjs ldr r2, [r0, r2, lsl #2] 272 1.1 rjs 273 1.4 bjh21 ldr r0, _C_LABEL(saipic_base) 274 1.1 rjs str r2, [r0, #(SAIPIC_MR)] /* Set mask register */ 275 1.1 rjs 276 1.1 rjs /* Restore old cpsr and exit */ 277 1.14 rafal msr cpsr_all, r1 278 1.14 rafal ldmia sp!, {r0, r1, r4, pc} /* Restore registers */ 279 1.1 rjs 280 1.1 rjs #ifdef IRQSTATS 281 1.1 rjs Lintrcnt: 282 1.1 rjs .word _C_LABEL(intrcnt) 283 1.1 rjs #endif 284 1.1 rjs 285 1.1 rjs Lirqhandlers: 286 1.1 rjs .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 287 1.1 rjs 288 1.1 rjs 289 1.1 rjs #ifdef IRQSTATS 290 1.5 chris .global _C_LABEL(intrnames), _C_LABEL(eintrnames) 291 1.5 chris .global _C_LABEL(eintrcnt) 292 1.19 skrll _C_LABEL(intrnames): 293 1.5 chris _C_LABEL(eintrnames): 294 1.5 chris _C_LABEL(eintrcnt): 295 1.5 chris 296 1.1 rjs .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt) 297 1.1 rjs 298 1.1 rjs _C_LABEL(intrcnt): 299 1.1 rjs .space ICU_LEN*4 /* XXX Should be linked to number of interrupts */ 300 1.1 rjs 301 1.1 rjs _C_LABEL(sintrcnt): 302 1.1 rjs .space 32*4 303 1.1 rjs #endif 304