1/* $NetBSD: sa11x0_irq.S,v 1.15 2010/12/20 00:25:29 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 52Lspl_masks: 53 .word _C_LABEL(spl_masks) 54 55Lcpu_info_store: 56 .word _C_LABEL(cpu_info_store) 57 58 .globl _C_LABEL(saipic_base) 59_C_LABEL(saipic_base): 60 .word 0x00000000 61 62#ifdef INTR_DEBUG 63Ldbg_str: 64 .asciz "irq_entry %x %x\n" 65 .align 5 66#endif 67 68LOCK_CAS_CHECK_LOCALS 69 70AST_ALIGNMENT_FAULT_LOCALS 71 72/* 73 * Register usage 74 * 75 * r6 - Address of current handler 76 * r7 - Pointer to handler pointer list 77 * r8 - Current IRQ requests. 78 * r9 - Used to count through possible IRQ bits. 79 * r10 - Base address of SAIP 80 */ 81 82ASENTRY_NP(irq_entry) 83 sub lr, lr, #0x00000004 /* Adjust the lr */ 84 85 PUSHFRAMEINSVC /* Push an interrupt frame */ 86 ENABLE_ALIGNMENT_FAULTS 87 88 /* Load r8 with the SAIPIC interrupt requests */ 89 90 ldr r10, _C_LABEL(saipic_base) 91 ldr r8, [r10, #(SAIPIC_IP)] /* Load IRQ pending register */ 92 93#ifdef INTR_DEBUG 94 ldr r2, [r10, #(SAIPIC_MR)] 95 adr r0, Ldbg_str 96 mov r1, r8 97 bl _C_LABEL(printf) 98#endif 99 /* 100 * Note that we have entered the IRQ handler. 101 * We are in SVC mode so we cannot use the processor mode 102 * to determine if we are in an IRQ. Instead we will count the 103 * each time the interrupt handler is nested. 104 */ 105 106 ldr r1, [r4, #CI_INTR_DEPTH] 107 add r1, r1, #1 108 str r1, [r4, #CI_INTR_DEPTH] 109 110 /* 111 * Need to block all interrupts at the IPL or lower for 112 * all asserted interrupts. 113 * This basically emulates hardware interrupt priority levels. 114 * Means we need to go through the interrupt mask and for 115 * every asserted interrupt we need to mask out all other 116 * interrupts at the same or lower IPL. 117 * If only we could wait until the main loop but we need to sort 118 * this out first so interrupts can be re-enabled. 119 * 120 * This would benefit from a special ffs type routine 121 */ 122 123 mov r9, #(NIPL - 1) 124 ldr r7, Lspl_masks 125 126Lfind_highest_ipl: 127 ldr r2, [r7, r9, lsl #2] 128 tst r8, r2 129 subeq r9, r9, #1 130 beq Lfind_highest_ipl 131 132 /* r9 = SPL level of highest priority interrupt */ 133 add r9, r9, #1 134 ldr r2, [r7, r9, lsl #2] 135 136 ldr r1, [r4, #CI_CPL] 137 str r9, [r4, #CI_CPL] 138 stmfd sp!, {r1} 139 140 /* Update the SAIP irq masks */ 141 bl _C_LABEL(irq_setmasks) 142 143#ifdef INTR_DEBUG 144 stmfd sp!, {r0,r1,r2} 145 adr r0, Ldbg_str 146 mov r1, #1 147 mov r2, r9 148 bl _C_LABEL(printf) 149 ldmia sp!, {r0,r1,r2} 150#endif 151 mrs r0, cpsr_all /* Enable IRQs */ 152 bic r0, r0, #I32_bit 153 msr cpsr_all, r0 154 155 ldr r7, Lirqhandlers 156 mov r9, #0x00000001 157 158irqloop: 159 /* This would benefit from a special ffs type routine */ 160 tst r8, r9 /* Is a bit set ? */ 161 beq nextirq /* No ? try next bit */ 162 163 ldr r6, [r7] /* Get address of first handler structure */ 164 165 teq r6, #0x00000000 /* Do we have a handler */ 166 moveq r0, r8 /* IRQ requests as arg 0 */ 167 beq _C_LABEL(stray_irqhandler) /* call special handler */ 168 169 ldr r0, [r4, #(CI_CC_NINTR)] 170 ldr r1, [r4, #(CI_CC_NINTR+4)] 171#ifdef _ARMEL 172 adds r0, r0, #0x00000001 173 adc r1, r1, #0x00000001 174#else 175 adds r1, r1, #0x00000001 176 adc r0, r0, #0x00000000 177#endif 178 str r0, [r4, #(CI_CC_NINTR)] 179 str r1, [r4, #(CI_CC_NINTR+4)] 180 181 /* 182 * XXX: Should stats be accumulated for every interrupt routine 183 * called or for every physical interrupt that is serviced. 184 */ 185 186#ifdef IRQSTATS 187 ldr r0, Lintrcnt 188 ldr r1, [r6, #(IH_COUNT)] 189 190 add r0, r0, r1, lsl #2 191 ldr r1, [r0] 192 add r1, r1, #0x00000001 193 str r1, [r0] 194#endif /* IRQSTATS */ 195 196irqchainloop: 197#ifdef INTR_DEBUG 198 stmfd sp!, {r0,r1,r2} 199 adr r0, Ldbg_str 200 mov r1, #2 201 bl _C_LABEL(printf) 202 ldmia sp!, {r0,r1,r2} 203#endif 204 ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 205 teq r0, #0x00000000 /* If arg is zero pass stack frame */ 206 addeq r0, sp, #4 /* ... stack frame [XXX needs care] */ 207 mov lr, pc /* return address */ 208 ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 209 210 teq r0, #0x00000001 /* Was the irq serviced ? */ 211 beq irqdone 212 213 ldr r6, [r6, #(IH_NEXT)] 214 teq r6, #0x00000000 215 bne irqchainloop 216 217irqdone: 218nextirq: 219 add r7, r7, #0x00000004 /* update pointer to handlers */ 220 mov r9, r9, lsl #1 /* move on to next bit */ 221 teq r9, #(1 << 31) /* done the last bit ? */ 222 bne irqloop /* no - loop back. */ 223 224 ldmfd sp!, {r2} 225 str r2, [r4, #CI_CPL] 226 227 /* Restore previous disabled mask */ 228 bl _C_LABEL(irq_setmasks) 229 230#ifdef __HAVE_FAST_SOFTINTS 231 bl _C_LABEL(dosoftints) /* Handle the soft interrupts */ 232#endif 233 234 /* Kill IRQ's in preparation for exit */ 235 mrs r0, cpsr_all 236 orr r0, r0, #(I32_bit) 237 msr cpsr_all, r0 238 239#ifdef INTR_DEBUG 240 adr r0, Ldbg_str 241 mov r1, #3 242 ldr r2, [r10, #(SAIPIC_MR)] 243 bl _C_LABEL(printf) 244#endif 245 246 /* Decrement the nest count */ 247 ldr r1, [r4, #CI_INTR_DEPTH] 248 sub r1, r1, #1 249 str r1, [r4, #CI_INTR_DEPTH] 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 stmfd sp!, {r0, r1, r4, lr} /* Preserve registers */ 261 262 /* Disable interrupts */ 263 mrs r1, cpsr_all 264 orr r3, r1, #(I32_bit) 265 msr cpsr_all, r3 266 267 /* Calculate interrupt mask */ 268 ldr r0, Lspl_masks 269 ldr r4, Lcpu_info_store 270 ldr r2, [r4, #CI_CPL] 271 ldr r2, [r0, r2, lsl #2] 272 273 ldr r0, _C_LABEL(saipic_base) 274 str r2, [r0, #(SAIPIC_MR)] /* Set mask register */ 275 276 /* Restore old cpsr and exit */ 277 msr cpsr_all, r1 278 ldmia sp!, {r0, r1, r4, pc} /* Restore registers */ 279 280#ifdef IRQSTATS 281Lintrcnt: 282 .word _C_LABEL(intrcnt) 283#endif 284 285Lirqhandlers: 286 .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 287 288 289#ifdef IRQSTATS 290 .global _C_LABEL(intrnames), _C_LABEL(eintrnames) 291 .global _C_LABEL(eintrcnt) 292_C_LABEL(intrnames): 293_C_LABEL(eintrnames): 294_C_LABEL(eintrcnt): 295 296 .globl _C_LABEL(intrcnt), _C_LABEL(sintrcnt) 297 298_C_LABEL(intrcnt): 299 .space ICU_LEN*4 /* XXX Should be linked to number of interrupts */ 300 301_C_LABEL(sintrcnt): 302 .space 32*4 303#endif 304