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