ofw_irq.S revision 1.2
11.2Sbjh21/* $NetBSD: ofw_irq.S,v 1.2 2002/10/14 22:32:52 bjh21 Exp $ */ 21.1Sthorpej 31.1Sthorpej/* 41.1Sthorpej * Copyright (c) 1994-1998 Mark Brinicombe. 51.1Sthorpej * Copyright (c) 1994 Brini. 61.1Sthorpej * All rights reserved. 71.1Sthorpej * 81.1Sthorpej * This code is derived from software written for Brini by Mark Brinicombe 91.1Sthorpej * 101.1Sthorpej * Redistribution and use in source and binary forms, with or without 111.1Sthorpej * modification, are permitted provided that the following conditions 121.1Sthorpej * are met: 131.1Sthorpej * 1. Redistributions of source code must retain the above copyright 141.1Sthorpej * notice, this list of conditions and the following disclaimer. 151.1Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 161.1Sthorpej * notice, this list of conditions and the following disclaimer in the 171.1Sthorpej * documentation and/or other materials provided with the distribution. 181.1Sthorpej * 3. All advertising materials mentioning features or use of this software 191.1Sthorpej * must display the following acknowledgement: 201.1Sthorpej * This product includes software developed by Mark Brinicombe 211.1Sthorpej * for the NetBSD Project. 221.1Sthorpej * 4. The name of the company nor the name of the author may be used to 231.1Sthorpej * endorse or promote products derived from this software without specific 241.1Sthorpej * prior written permission. 251.1Sthorpej * 261.1Sthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 271.1Sthorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 281.1Sthorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 291.1Sthorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 301.1Sthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 311.1Sthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321.1Sthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331.1Sthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341.1Sthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 351.1Sthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361.1Sthorpej * 371.1Sthorpej * Low level irq and fiq handlers 381.1Sthorpej * 391.1Sthorpej * Created : 27/09/94 401.1Sthorpej */ 411.1Sthorpej 421.1Sthorpej#include "opt_irqstats.h" 431.1Sthorpej 441.1Sthorpej#include "assym.h" 451.1Sthorpej#include <machine/asm.h> 461.1Sthorpej#include <machine/cpu.h> 471.1Sthorpej#include <machine/frame.h> 481.1Sthorpej#include <machine/irqhandler.h> 491.1Sthorpej 501.1Sthorpej .text 511.1Sthorpej .align 0 521.1Sthorpej 531.1Sthorpej/* 541.1Sthorpej * 551.1Sthorpej * irq_entry 561.1Sthorpej * 571.1Sthorpej * Main entry point for the IRQ vector 581.1Sthorpej * 591.1Sthorpej * This function is called only on timer ticks, passed on to the 601.1Sthorpej * kernel from the OFW tick handler. 611.1Sthorpej * 621.1Sthorpej * For now, I am trying to re-use as much of the code from the 631.1Sthorpej * IOMD interrupt-handler as possible. In time, I will strip this 641.1Sthorpej * down to something OFW-specific. 651.1Sthorpej * 661.1Sthorpej * Here's the original, IOMD-specific description: 671.1Sthorpej * This function reads the irq request bits in the IOMD registers 681.1Sthorpej * IRQRQA, IRQRQB and DMARQ 691.1Sthorpej * It then calls an installed handler for each bit that is set. 701.1Sthorpej * The function stray_irqhandler is called if a handler is not defined 711.1Sthorpej * for a particular interrupt. 721.1Sthorpej * If a interrupt handler is found then it is called with r0 containing 731.1Sthorpej * the argument defined in the handler structure. If the field ih_arg 741.1Sthorpej * is zero then a pointer to the IRQ frame on the stack is passed instead. 751.1Sthorpej */ 761.1Sthorpej 771.1SthorpejLdisabled_mask: 781.1Sthorpej .word _C_LABEL(disabled_mask) 791.1Sthorpej 801.1SthorpejLcurrent_spl_level: 811.1Sthorpej .word _C_LABEL(current_spl_level) 821.1Sthorpej 831.1SthorpejLcurrent_intr_depth: 841.1Sthorpej .word _C_LABEL(current_intr_depth) 851.1Sthorpej 861.1SthorpejLspl_masks: 871.1Sthorpej .word _C_LABEL(spl_masks) 881.1Sthorpej 891.1SthorpejLofw_ticktmp: 901.1Sthorpej .word _C_LABEL(ofw_ticktmp) 911.1Sthorpej 921.1SthorpejLirq_entry: 931.1Sthorpej .word irq_entry 941.1Sthorpej 951.1SthorpejLofwirqstk: /* hack */ 961.1Sthorpej .word ofwirqstk + 4096 971.1Sthorpej 981.1Sthorpej/* 991.1Sthorpej * Regsister usage 1001.1Sthorpej * 1011.1Sthorpej * r6 - Address of current handler 1021.1Sthorpej * r7 - Pointer to handler pointer list 1031.1Sthorpej * r8 - Current IRQ requests. 1041.1Sthorpej * r9 - Used to count through possible IRQ bits. 1051.1Sthorpej * r10 - Base address of IOMD 1061.1Sthorpej */ 1071.1Sthorpej 1081.1SthorpejASENTRY_NP(irq_entry) 1091.1Sthorpej /* 1101.1Sthorpej * We come here following an OFW-handled timer tick. 1111.1Sthorpej * 1121.1Sthorpej * We are in the SVC frame, and interrupts are disabled. 1131.1Sthorpej * The state of the interrupted context is partially in 1141.1Sthorpej * the registers and partially in the global storage area 1151.1Sthorpej * labeled ofw_ticktmp. ofw_ticktmp is filled-in by the 1161.1Sthorpej * tick callback that is invoked by OFW on the way out of 1171.1Sthorpej * its interrupt handler. ofw_ticktmp contains the following: 1181.1Sthorpej * 1191.1Sthorpej * pc // interrupted instruction 1201.1Sthorpej * lr_usr 1211.1Sthorpej * sp_usr 1221.1Sthorpej * r1 // makes r1 available for scratch 1231.1Sthorpej * r0 // makes r0 available for scratch 1241.1Sthorpej * spsr_svc // cpsr of interrupted context 1251.1Sthorpej * 1261.1Sthorpej * The prologue of this routine must re-construct the 1271.1Sthorpej * machine state that existed at the time OFW's interrupt- 1281.1Sthorpej * handler fielded the interrupt. That allows us to use 1291.1Sthorpej * the rest of the code in this routine, and have it all 1301.1Sthorpej * "just work." 1311.1Sthorpej */ 1321.1Sthorpej 1331.1Sthorpej /* 1341.1Sthorpej * Switch to IRQ mode. 1351.1Sthorpej * First check the spsr in ofw_ticktmp to see what the FIQ bit should be. 1361.1Sthorpej * 1371.1Sthorpej * I need 2 scratch registers to do this. 1381.1Sthorpej * Fortunately, r0 and r1 are already saved in ofw_ticktmp. 1391.1Sthorpej * How convenient. 1401.1Sthorpej */ 1411.1Sthorpej ldr r0, Lofw_ticktmp 1421.1Sthorpej ldr r0, [r0] 1431.1Sthorpej and r0, r0, #F32_bit 1441.1Sthorpej mov r1, #(I32_bit | PSR_IRQ32_MODE) 1451.1Sthorpej orr r1, r1, r0 1461.1Sthorpej msr cpsr_all, r1 1471.1Sthorpej 1481.1Sthorpej /* Now we're in IRQ mode. */ 1491.1Sthorpej /* Restore contents of ofw_ticktmp. */ 1501.2Sbjh21 adr r0, Lofwirqstk /* Bummer! Mitch hasn't left me a stack. */ 1511.2Sbjh21 ldr sp, [r0] /* I'll use my own for now... */ 1521.1Sthorpej ldr r0, Lofw_ticktmp /* r0 now points to ofw_ticktmp[0] */ 1531.1Sthorpej ldr r1, [r0], #(4*3) /* skip over saved {r0, r1} */ 1541.1Sthorpej msr spsr_all, r1 /* restore spsr */ 1551.1Sthorpej ldmia r0, {sp, lr}^ /* restore user sp and lr */ 1561.1Sthorpej add r0, r0, #(4*2) /* previous instruction can't writeback */ 1571.1Sthorpej /* this one can't use banked registers */ 1581.1Sthorpej ldr lr, [r0], #(-4*4) /* restore pc; point r0 at ofw_ticktmp[1] */ 1591.1Sthorpej add lr, lr, #4 /* pc += 4; will be decremented below */ 1601.1Sthorpej ldmia r0, {r0, r1} /* restore r0 and r1 */ 1611.1Sthorpej 1621.1Sthorpej /* OK, the machine state should be identical now to that when */ 1631.1Sthorpej /* OFW fielded the interrupt. So just fall through... */ 1641.1Sthorpej 1651.1Sthorpej sub lr, lr, #0x00000004 /* Adjust the lr */ 1661.1Sthorpej 1671.1Sthorpej PUSHFRAMEINSVC /* Push an interrupt frame */ 1681.1Sthorpej 1691.1Sthorpej /* 1701.1Sthorpej * Can't field this interrupt now if priority is _SPL_CLOCK 1711.1Sthorpej * or higher. For now, we'll just ignore the interrupt. 1721.1Sthorpej * Soon, we will have to schedule it for later action. 1731.1Sthorpej */ 1741.1Sthorpej ldr r0, Lcurrent_spl_level 1751.1Sthorpej ldr r0, [r0] 1761.1Sthorpej cmp r0, #_SPL_CLOCK 1771.1Sthorpej blt ofwtakeint 1781.1Sthorpej 1791.1Sthorpej PULLFRAMEFROMSVCANDEXIT 1801.1Sthorpej movs pc, lr /* Exit */ 1811.1Sthorpej 1821.1Sthorpej /* 1831.1Sthorpej * Stuff a bit-mask into r8 indicating which interrupts 1841.1Sthorpej * are pending. In our case, that is just the timer0 1851.1Sthorpej * interrupt: (1 << TIMER0). The existing code will take 1861.1Sthorpej * care of invoking that handler and the softint/ast stuff 1871.1Sthorpej * which follows it. 1881.1Sthorpej */ 1891.1Sthorpejofwtakeint: 1901.1Sthorpej mov r8, #0x00000001 /* timer interrupt pending! */ 1911.1Sthorpej mov r8, r8, lsl #IRQ_TIMER0 1921.1Sthorpej 1931.1Sthorpej /* 1941.1Sthorpej * Note that we have entered the IRQ handler. 1951.1Sthorpej * We are in SVC mode so we cannot use the processor mode 1961.1Sthorpej * to determine if we are in an IRQ. Instead we will count the 1971.1Sthorpej * each time the interrupt handler is nested. 1981.1Sthorpej */ 1991.1Sthorpej 2001.1Sthorpej ldr r0, Lcurrent_intr_depth 2011.1Sthorpej ldr r1, [r0] 2021.1Sthorpej add r1, r1, #1 2031.1Sthorpej str r1, [r0] 2041.1Sthorpej 2051.1Sthorpej /* Block the current requested interrupts */ 2061.1Sthorpej ldr r1, Ldisabled_mask 2071.1Sthorpej ldr r0, [r1] 2081.1Sthorpej stmfd sp!, {r0} 2091.1Sthorpej orr r0, r0, r8 2101.1Sthorpej 2111.1Sthorpej /* 2121.1Sthorpej * Need to block all interrupts at the IPL or lower for 2131.1Sthorpej * all asserted interrupts. 2141.1Sthorpej * This basically emulates hardware interrupt priority levels. 2151.1Sthorpej * Means we need to go through the interrupt mask and for 2161.1Sthorpej * every asserted interrupt we need to mask out all other 2171.1Sthorpej * interrupts at the same or lower IPL. 2181.1Sthorpej * If only we could wait until the main loop but we need to sort 2191.1Sthorpej * this out first so interrupts can be re-enabled. 2201.1Sthorpej * 2211.1Sthorpej * This would benefit from a special ffs type routine 2221.1Sthorpej */ 2231.1Sthorpej 2241.1Sthorpej mov r9, #(_SPL_LEVELS - 1) 2251.1Sthorpej ldr r7, Lspl_masks 2261.1Sthorpej 2271.1SthorpejLfind_highest_ipl: 2281.1Sthorpej ldr r2, [r7, r9, lsl #2] 2291.1Sthorpej tst r8, r2 2301.1Sthorpej subeq r9, r9, #1 2311.1Sthorpej beq Lfind_highest_ipl 2321.1Sthorpej 2331.1Sthorpej /* r9 = SPL level of highest priority interrupt */ 2341.1Sthorpej add r9, r9, #1 2351.1Sthorpej ldr r2, [r7, r9, lsl #2] 2361.1Sthorpej mvn r2, r2 2371.1Sthorpej orr r0, r0, r2 2381.1Sthorpej 2391.1Sthorpej str r0, [r1] 2401.1Sthorpej 2411.1Sthorpej ldr r0, Lcurrent_spl_level 2421.1Sthorpej ldr r1, [r0] 2431.1Sthorpej str r9, [r0] 2441.1Sthorpej stmfd sp!, {r1} 2451.1Sthorpej 2461.1Sthorpej /* Update the irq masks */ 2471.1Sthorpej bl _C_LABEL(irq_setmasks) 2481.1Sthorpej 2491.1Sthorpej mrs r0, cpsr_all /* Enable IRQ's */ 2501.1Sthorpej bic r0, r0, #I32_bit 2511.1Sthorpej msr cpsr_all, r0 2521.1Sthorpej 2531.2Sbjh21 ldr r7, Lirqhandlers 2541.1Sthorpej mov r9, #0x00000001 2551.1Sthorpej 2561.1Sthorpejirqloop: 2571.1Sthorpej /* This would benefit from a special ffs type routine */ 2581.1Sthorpej tst r8, r9 /* Is a bit set ? */ 2591.1Sthorpej beq nextirq /* No ? try next bit */ 2601.1Sthorpej 2611.1Sthorpej ldr r6, [r7] /* Get address of first handler structure */ 2621.1Sthorpej 2631.1Sthorpej teq r6, #0x00000000 /* Do we have a handler */ 2641.1Sthorpej moveq r0, r8 /* IRQ requests as arg 0 */ 2651.1Sthorpej beq _C_LABEL(stray_irqhandler) /* call special handler */ 2661.1Sthorpej 2671.1Sthorpej ldr r0, Lcnt 2681.1Sthorpej ldr r1, [r0, #(V_INTR)] 2691.1Sthorpej add r1, r1, #0x00000001 2701.1Sthorpej str r1, [r0, #(V_INTR)] 2711.1Sthorpej 2721.1Sthorpej/* 2731.1Sthorpej * XXX: Should stats be accumlated for every interrupt routine called 2741.1Sthorpej * or for every physical interrupt that is serviced. 2751.1Sthorpej */ 2761.1Sthorpej 2771.1Sthorpej#ifdef IRQSTATS 2781.1Sthorpej ldr r0, Lintrcnt 2791.1Sthorpej ldr r1, [r6, #(IH_NUM)] 2801.1Sthorpej 2811.1Sthorpej add r0, r0, r1, lsl #2 2821.1Sthorpej ldr r1, [r0] 2831.1Sthorpej add r1, r1, #0x00000001 2841.1Sthorpej str r1, [r0] 2851.1Sthorpej#endif /* IRQSTATS */ 2861.1Sthorpej 2871.1Sthorpejirqchainloop: 2881.1Sthorpej ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 2891.1Sthorpej teq r0, #0x00000000 /* If arg is zero pass stack frame */ 2901.1Sthorpej addeq r0, sp, #8 /* ... stack frame */ 2911.2Sbjh21 mov lr, pc /* return address */ 2921.1Sthorpej ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 2931.1Sthorpej 2941.1Sthorpej teq r0, #0x00000001 /* Was the irq serviced ? */ 2951.1Sthorpej beq irqdone 2961.1Sthorpej 2971.1Sthorpej ldr r6, [r6, #(IH_NEXT)] 2981.1Sthorpej teq r6, #0x00000000 2991.1Sthorpej bne irqchainloop 3001.1Sthorpej 3011.1Sthorpejirqdone: 3021.1Sthorpejnextirq: 3031.1Sthorpej add r7, r7, #0x00000004 /* update pointer to handlers */ 3041.1Sthorpej mov r9, r9, lsl #1 /* move on to next bit */ 3051.1Sthorpej teq r9, #(1 << 24) /* done the last bit ? */ 3061.1Sthorpej bne irqloop /* no - loop back. */ 3071.1Sthorpej 3081.1Sthorpej ldmfd sp!, {r2} 3091.1Sthorpej ldr r1, Lcurrent_spl_level 3101.1Sthorpej str r2, [r1] 3111.1Sthorpej 3121.1Sthorpej /* Restore previous disabled mask */ 3131.1Sthorpej ldmfd sp!, {r2} 3141.1Sthorpej ldr r1, Ldisabled_mask 3151.1Sthorpej str r2, [r1] 3161.1Sthorpej bl _C_LABEL(irq_setmasks) 3171.1Sthorpej 3181.1Sthorpej bl _C_LABEL(dosoftints) /* Handle the soft interrupts */ 3191.1Sthorpej 3201.1Sthorpej /* Manage AST's. Maybe this should be done as a soft interrupt ? */ 3211.1Sthorpej ldr r0, [sp] /* Get the SPSR from stack */ 3221.1Sthorpej 3231.1Sthorpej and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the IRQ */ 3241.1Sthorpej teq r0, #(PSR_USR32_MODE) 3251.1Sthorpej ldreq r0, Lastpending /* Do we have an AST pending ? */ 3261.1Sthorpej ldreq r1, [r0] 3271.1Sthorpej teqeq r1, #0x00000001 3281.1Sthorpej 3291.1Sthorpej beq irqast /* call the AST handler */ 3301.1Sthorpej 3311.1Sthorpej /* Kill IRQ's in preparation for exit */ 3321.1Sthorpej mrs r0, cpsr_all 3331.1Sthorpej orr r0, r0, #(I32_bit) 3341.1Sthorpej msr cpsr_all, r0 3351.1Sthorpej 3361.1Sthorpej /* Decrement the nest count */ 3371.1Sthorpej ldr r0, Lcurrent_intr_depth 3381.1Sthorpej ldr r1, [r0] 3391.1Sthorpej sub r1, r1, #1 3401.1Sthorpej str r1, [r0] 3411.1Sthorpej 3421.1Sthorpej PULLFRAMEFROMSVCANDEXIT 3431.1Sthorpej 3441.1Sthorpej movs pc, lr /* Exit */ 3451.1Sthorpej 3461.1Sthorpej /* 3471.1Sthorpej * Ok, snag with current intr depth ... 3481.1Sthorpej * If ast() calls mi_sleep() the current_intr_depth will not be 3491.1Sthorpej * decremented until the process is woken up. This can result 3501.1Sthorpej * in the system believing it is still in the interrupt handler. 3511.1Sthorpej * If we are calling ast() then correct the current_intr_depth 3521.1Sthorpej * before the call. 3531.1Sthorpej */ 3541.1Sthorpejirqast: 3551.1Sthorpej mov r1, #0x00000000 /* Clear ast_pending */ 3561.1Sthorpej str r1, [r0] 3571.1Sthorpej 3581.1Sthorpej /* Kill IRQ's so we atomically decrement current_intr_depth */ 3591.1Sthorpej 3601.1Sthorpej mrs r2, cpsr_all 3611.1Sthorpej orr r3, r2, #(I32_bit) 3621.1Sthorpej msr cpsr_all, r3 3631.1Sthorpej 3641.1Sthorpej /* Decrement the nest count */ 3651.1Sthorpej 3661.1Sthorpej ldr r0, Lcurrent_intr_depth 3671.1Sthorpej ldr r1, [r0] 3681.1Sthorpej sub r1, r1, #1 3691.1Sthorpej str r1, [r0] 3701.1Sthorpej 3711.1Sthorpej /* Restore IRQ's */ 3721.1Sthorpej msr cpsr_all, r2 3731.1Sthorpej 3741.1Sthorpej mov r0, sp 3751.1Sthorpej bl _C_LABEL(ast) 3761.1Sthorpej 3771.1Sthorpej/* Kill IRQ's in preparation for exit */ 3781.1Sthorpej 3791.1Sthorpej mrs r0, cpsr_all 3801.1Sthorpej orr r0, r0, #(I32_bit) 3811.1Sthorpej msr cpsr_all, r0 3821.1Sthorpej 3831.1Sthorpej PULLFRAMEFROMSVCANDEXIT 3841.1Sthorpej 3851.1Sthorpej movs pc, lr /* Exit */ 3861.1Sthorpej 3871.1Sthorpej 3881.1SthorpejLspl_mask: 3891.1Sthorpej .word _C_LABEL(spl_mask) /* irq's allowed at current spl level */ 3901.1Sthorpej 3911.1SthorpejLcurrent_mask: 3921.1Sthorpej .word _C_LABEL(current_mask) /* irq's that are usable */ 3931.1Sthorpej 3941.1Sthorpej 3951.1SthorpejENTRY(irq_setmasks) 3961.1Sthorpej /* Do nothing */ 3971.1Sthorpej mov pc, lr 3981.1Sthorpej 3991.1Sthorpej 4001.1SthorpejLcnt: 4011.1Sthorpej .word _C_LABEL(uvmexp) 4021.1Sthorpej 4031.1SthorpejLintrcnt: 4041.1Sthorpej .word _C_LABEL(intrcnt) 4051.1Sthorpej 4061.1Sthorpej 4071.1SthorpejLirqhandlers: 4081.1Sthorpej .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 4091.1Sthorpej 4101.1SthorpejLastpending: 4111.1Sthorpej .word _C_LABEL(astpending) 4121.1Sthorpej 4131.1Sthorpej .text 4141.1Sthorpej .global _C_LABEL(dotickgrovelling) 4151.1Sthorpej 4161.1Sthorpej/* 4171.1Sthorpej * Do magic to cause OFW to call our irq_entry 4181.1Sthorpej * routine when it returns from its tick-handling. 4191.1Sthorpej * 4201.1Sthorpej * This consists of two sub-tasks: 4211.1Sthorpej * - save some machine state in ofw_ticktmp 4221.1Sthorpej * - punch some new machine state into the 4231.1Sthorpej * OFW-supplied frame 4241.1Sthorpej * 4251.1Sthorpej * We are running in the IRQ frame, with 4261.1Sthorpej * interrupts disabled. 4271.1Sthorpej * 4281.1Sthorpej * r0 - base of saved OFW interrupt frame, which 4291.1Sthorpej * has the following format: 4301.1Sthorpej * 4311.1Sthorpej * pc // interrupted instruction 4321.1Sthorpej * lr // lr of interrupted context 4331.1Sthorpej * sp // sp of interrupted context 4341.1Sthorpej * r12 4351.1Sthorpej * ... // non-banked register values 4361.1Sthorpej * ... // of interrupted context 4371.1Sthorpej * r0 4381.1Sthorpej * spsr // psr of interrupted context 4391.1Sthorpej * 4401.1Sthorpej */ 4411.1Sthorpej 4421.1Sthorpej_C_LABEL(dotickgrovelling): 4431.1Sthorpej /*assert((cpsr & PSR_MODE) == PSR_IRQ32_MODE);*/ 4441.1Sthorpej 4451.1Sthorpej stmfd sp!, {r1-r5} /* scratch registers r1-r5 */ 4461.1Sthorpej 4471.1Sthorpej /* 4481.1Sthorpej * Sub-task 1: 4491.1Sthorpej * 4501.1Sthorpej * Our irq_entry routine needs to re-construct 4511.1Sthorpej * the state of the machine at the time OFW 4521.1Sthorpej * fielded the interrupt, so that we can use 4531.1Sthorpej * the rest of the standard interrupt-handling 4541.1Sthorpej * code. Specifically, irq_entry needs to get 4551.1Sthorpej * at the following machine state: 4561.1Sthorpej * 4571.1Sthorpej * pc // interrupted instruction 4581.1Sthorpej * lr_usr 4591.1Sthorpej * sp_usr 4601.1Sthorpej * r0-r12 // the non-banked registers 4611.1Sthorpej * // at the time of interruption 4621.1Sthorpej * spsr // cpsr of interrupted context 4631.1Sthorpej * 4641.1Sthorpej * The non-banked registers will be valid at the 4651.1Sthorpej * time irq_entry is called, but the other values 4661.1Sthorpej * will not be. We must save them here, in the 4671.1Sthorpej * ofw_ticktmp storage block. We also save r0 4681.1Sthorpej * and r1 so that we have some free registers 4691.1Sthorpej * when it's time to do the re-construction. 4701.1Sthorpej * 4711.1Sthorpej * Note that interrupts are not enabled before 4721.1Sthorpej * irq_entry is entered, so we don't have to 4731.1Sthorpej * worry about ofw_ticktmp getting clobbered. 4741.1Sthorpej */ 4751.1Sthorpej ldr r1, Lofw_ticktmp /* r1 points to ofw_ticktmp[0] */ 4761.1Sthorpej 4771.1Sthorpej ldr r2, [r0, #0] /* ofwframe[0] is spsr */ 4781.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[0] */ 4791.1Sthorpej 4801.1Sthorpej ldr r2, [r0, #(4*1)] /* ofwframe[1] is saved r0 */ 4811.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[1] */ 4821.1Sthorpej 4831.1Sthorpej ldr r2, [r0, #(4*2)] /* ofwframe[2] is saved r1 */ 4841.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[2] */ 4851.1Sthorpej 4861.1Sthorpej stmia r1, {sp, lr}^ /* put {sp,lr}_usr in ofw_ticktmp[3,4]; */ 4871.1Sthorpej /* the user registers are still valid */ 4881.1Sthorpej /* because we haven't left IRQ mode */ 4891.1Sthorpej add r1, r1, #(4*2) /* previous instruction can't writeback */ 4901.1Sthorpej /* this one can't use banked registers */ 4911.1Sthorpej 4921.1Sthorpej ldr r2, [r0, #(4*16)] /* ofwframe[16] is pc */ 4931.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[5] */ 4941.1Sthorpej 4951.1Sthorpej 4961.1Sthorpej /* 4971.1Sthorpej * Sub-task 2: 4981.1Sthorpej * 4991.1Sthorpej * Diddle the OFW-supplied frame such that 5001.1Sthorpej * control passes to irq_entry when OFW does 5011.1Sthorpej * its return from interrupt. There are 4 5021.1Sthorpej * fields in that frame that we need to plug: 5031.1Sthorpej * 5041.1Sthorpej * pc // gets irq_entry 5051.1Sthorpej * lr // gets lr_svc 5061.1Sthorpej * sp // gets sp_svc 5071.1Sthorpej * spsr // gets (I32_bit | PSR_SVC32_MODE) 5081.1Sthorpej * 5091.1Sthorpej */ 5101.1Sthorpej mov r1, #(I32_bit | PSR_SVC32_MODE) 5111.1Sthorpej str r1, [r0, #0] /* plug spsr */ 5121.1Sthorpej 5131.1Sthorpej /* Sneak into SVC mode to get sp and lr */ 5141.1Sthorpej mrs r3, cpsr_all 5151.1Sthorpej bic r3, r3, #(PSR_MODE) 5161.1Sthorpej orr r3, r3, #(PSR_SVC32_MODE) 5171.1Sthorpej msr cpsr_all, r3 5181.1Sthorpej mov r4, lr /* snarf lr_svc */ 5191.1Sthorpej mov r5, sp /* snarf sp_svc */ 5201.1Sthorpej bic r3, r3, #(PSR_MODE) 5211.1Sthorpej orr r3, r3, #(PSR_IRQ32_MODE) 5221.1Sthorpej msr cpsr_all, r3 5231.1Sthorpej str r5, [r0, #(4*14)] /* plug sp */ 5241.1Sthorpej str r4, [r0, #(4*15)] /* plug lr */ 5251.1Sthorpej 5261.2Sbjh21 ldr r1, Lirq_entry 5271.1Sthorpej str r1, [r0, #(4*16)] /* plug pc */ 5281.1Sthorpej 5291.1Sthorpej ldmfd sp!, {r1-r5} 5301.1Sthorpej mov pc, lr 5311.1Sthorpej 5321.1Sthorpej 5331.1Sthorpej .bss 5341.1Sthorpej .align 0 5351.1Sthorpej 5361.1Sthorpej_C_LABEL(ofw_ticktmp): 5371.1Sthorpej .space 4 * 6 /* temporary storage for 6 words of machine state */ 5381.1Sthorpej 5391.1Sthorpejofwirqstk: /* hack */ 5401.1Sthorpej .space 4096 5411.1Sthorpej 5421.1Sthorpej#ifdef IRQSTATS 5431.1Sthorpej/* These symbols are used by vmstat */ 5441.1Sthorpej 5451.1Sthorpej .text 5461.1Sthorpej .global _C_LABEL(_intrnames) 5471.1Sthorpej_C_LABEL(_intrnames): 5481.1Sthorpej .word _C_LABEL(intrnames) 5491.1Sthorpej 5501.1Sthorpej .data 5511.1Sthorpej 5521.1Sthorpej .globl _C_LABEL(intrnames), _C_LABEL(eintrnames), _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt) 5531.1Sthorpej_C_LABEL(intrnames): 5541.1Sthorpej .asciz "interrupt 0 " 5551.1Sthorpej .asciz "interrupt 1 " 5561.1Sthorpej .asciz "interrupt 2 " 5571.1Sthorpej .asciz "interrupt 3 " 5581.1Sthorpej .asciz "interrupt 4 " 5591.1Sthorpej .asciz "interrupt 5 " 5601.1Sthorpej .asciz "interrupt 6 " 5611.1Sthorpej .asciz "interrupt 7 " 5621.1Sthorpej .asciz "interrupt 8 " 5631.1Sthorpej .asciz "interrupt 9 " 5641.1Sthorpej .asciz "interrupt 10 " 5651.1Sthorpej .asciz "interrupt 11 " 5661.1Sthorpej .asciz "interrupt 12 " 5671.1Sthorpej .asciz "interrupt 13 " 5681.1Sthorpej .asciz "interrupt 14 " 5691.1Sthorpej .asciz "interrupt 15 " 5701.1Sthorpej .asciz "interrupt 16 " 5711.1Sthorpej .asciz "interrupt 17 " 5721.1Sthorpej .asciz "interrupt 18 " 5731.1Sthorpej .asciz "interrupt 19 " 5741.1Sthorpej .asciz "interrupt 20 " 5751.1Sthorpej .asciz "interrupt 21 " 5761.1Sthorpej .asciz "interrupt 22 " 5771.1Sthorpej .asciz "interrupt 23 " 5781.1Sthorpej .asciz "interrupt 24 " 5791.1Sthorpej .asciz "interrupt 25 " 5801.1Sthorpej .asciz "interrupt 26 " 5811.1Sthorpej .asciz "interrupt 27 " 5821.1Sthorpej .asciz "interrupt 28 " 5831.1Sthorpej .asciz "interrupt 29 " 5841.1Sthorpej .asciz "interrupt 30 " 5851.1Sthorpej .asciz "interrupt 31 " 5861.1Sthorpej 5871.1Sthorpej_C_LABEL(sintrnames): 5881.1Sthorpej .asciz "softclock " 5891.1Sthorpej .asciz "softnet " 5901.1Sthorpej .asciz "softserial " 5911.1Sthorpej .asciz "softintr 3 " 5921.1Sthorpej .asciz "softintr 4 " 5931.1Sthorpej .asciz "softintr 5 " 5941.1Sthorpej .asciz "softintr 6 " 5951.1Sthorpej .asciz "softintr 7 " 5961.1Sthorpej .asciz "softintr 8 " 5971.1Sthorpej .asciz "softintr 9 " 5981.1Sthorpej .asciz "softintr 10 " 5991.1Sthorpej .asciz "softintr 11 " 6001.1Sthorpej .asciz "softintr 12 " 6011.1Sthorpej .asciz "softintr 13 " 6021.1Sthorpej .asciz "softintr 14 " 6031.1Sthorpej .asciz "softintr 15 " 6041.1Sthorpej .asciz "softintr 16 " 6051.1Sthorpej .asciz "softintr 17 " 6061.1Sthorpej .asciz "softintr 18 " 6071.1Sthorpej .asciz "softintr 19 " 6081.1Sthorpej .asciz "softintr 20 " 6091.1Sthorpej .asciz "softintr 21 " 6101.1Sthorpej .asciz "softintr 22 " 6111.1Sthorpej .asciz "softintr 23 " 6121.1Sthorpej .asciz "softintr 24 " 6131.1Sthorpej .asciz "softintr 25 " 6141.1Sthorpej .asciz "softintr 26 " 6151.1Sthorpej .asciz "softintr 27 " 6161.1Sthorpej .asciz "softintr 28 " 6171.1Sthorpej .asciz "softintr 29 " 6181.1Sthorpej .asciz "softintr 30 " 6191.1Sthorpej .asciz "softintr 31 " 6201.1Sthorpej_C_LABEL(eintrnames): 6211.1Sthorpej 6221.1Sthorpej .bss 6231.1Sthorpej .align 0 6241.1Sthorpej_C_LABEL(intrcnt): 6251.1Sthorpej .space 32*4 /* XXX Should be linked to number of interrupts */ 6261.1Sthorpej 6271.1Sthorpej_C_LABEL(sintrcnt): 6281.1Sthorpej .space 32*4 /* XXX Should be linked to number of interrupts */ 6291.1Sthorpej_C_LABEL(eintrcnt): 6301.1Sthorpej 6311.1Sthorpej#else /* IRQSTATS */ 6321.1Sthorpej/* Dummy entries to keep vmstat happy */ 6331.1Sthorpej 6341.1Sthorpej .text 6351.1Sthorpej .globl _C_LABEL(intrnames), _C_LABEL(eintrnames), _C_LABEL(intrcnt), _C_LABEL(eintrcnt) 6361.1Sthorpej_C_LABEL(intrnames): 6371.1Sthorpej .long 0 6381.1Sthorpej_C_LABEL(eintrnames): 6391.1Sthorpej 6401.1Sthorpej_C_LABEL(intrcnt): 6411.1Sthorpej .long 0 6421.1Sthorpej_C_LABEL(eintrcnt): 6431.1Sthorpej#endif /* IRQSTATS */ 644