ofw_irq.S revision 1.3
11.3Sscw/* $NetBSD: ofw_irq.S,v 1.3 2003/11/05 21:10:59 scw 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.3SscwAST_ALIGNMENT_FAULT_LOCALS 991.3Sscw 1001.1Sthorpej/* 1011.1Sthorpej * Regsister usage 1021.1Sthorpej * 1031.1Sthorpej * r6 - Address of current handler 1041.1Sthorpej * r7 - Pointer to handler pointer list 1051.1Sthorpej * r8 - Current IRQ requests. 1061.1Sthorpej * r9 - Used to count through possible IRQ bits. 1071.1Sthorpej * r10 - Base address of IOMD 1081.1Sthorpej */ 1091.1Sthorpej 1101.1SthorpejASENTRY_NP(irq_entry) 1111.1Sthorpej /* 1121.1Sthorpej * We come here following an OFW-handled timer tick. 1131.1Sthorpej * 1141.1Sthorpej * We are in the SVC frame, and interrupts are disabled. 1151.1Sthorpej * The state of the interrupted context is partially in 1161.1Sthorpej * the registers and partially in the global storage area 1171.1Sthorpej * labeled ofw_ticktmp. ofw_ticktmp is filled-in by the 1181.1Sthorpej * tick callback that is invoked by OFW on the way out of 1191.1Sthorpej * its interrupt handler. ofw_ticktmp contains the following: 1201.1Sthorpej * 1211.1Sthorpej * pc // interrupted instruction 1221.1Sthorpej * lr_usr 1231.1Sthorpej * sp_usr 1241.1Sthorpej * r1 // makes r1 available for scratch 1251.1Sthorpej * r0 // makes r0 available for scratch 1261.1Sthorpej * spsr_svc // cpsr of interrupted context 1271.1Sthorpej * 1281.1Sthorpej * The prologue of this routine must re-construct the 1291.1Sthorpej * machine state that existed at the time OFW's interrupt- 1301.1Sthorpej * handler fielded the interrupt. That allows us to use 1311.1Sthorpej * the rest of the code in this routine, and have it all 1321.1Sthorpej * "just work." 1331.1Sthorpej */ 1341.1Sthorpej 1351.1Sthorpej /* 1361.1Sthorpej * Switch to IRQ mode. 1371.1Sthorpej * First check the spsr in ofw_ticktmp to see what the FIQ bit should be. 1381.1Sthorpej * 1391.1Sthorpej * I need 2 scratch registers to do this. 1401.1Sthorpej * Fortunately, r0 and r1 are already saved in ofw_ticktmp. 1411.1Sthorpej * How convenient. 1421.1Sthorpej */ 1431.1Sthorpej ldr r0, Lofw_ticktmp 1441.1Sthorpej ldr r0, [r0] 1451.1Sthorpej and r0, r0, #F32_bit 1461.1Sthorpej mov r1, #(I32_bit | PSR_IRQ32_MODE) 1471.1Sthorpej orr r1, r1, r0 1481.1Sthorpej msr cpsr_all, r1 1491.1Sthorpej 1501.1Sthorpej /* Now we're in IRQ mode. */ 1511.1Sthorpej /* Restore contents of ofw_ticktmp. */ 1521.2Sbjh21 adr r0, Lofwirqstk /* Bummer! Mitch hasn't left me a stack. */ 1531.2Sbjh21 ldr sp, [r0] /* I'll use my own for now... */ 1541.1Sthorpej ldr r0, Lofw_ticktmp /* r0 now points to ofw_ticktmp[0] */ 1551.1Sthorpej ldr r1, [r0], #(4*3) /* skip over saved {r0, r1} */ 1561.1Sthorpej msr spsr_all, r1 /* restore spsr */ 1571.1Sthorpej ldmia r0, {sp, lr}^ /* restore user sp and lr */ 1581.1Sthorpej add r0, r0, #(4*2) /* previous instruction can't writeback */ 1591.1Sthorpej /* this one can't use banked registers */ 1601.1Sthorpej ldr lr, [r0], #(-4*4) /* restore pc; point r0 at ofw_ticktmp[1] */ 1611.1Sthorpej add lr, lr, #4 /* pc += 4; will be decremented below */ 1621.1Sthorpej ldmia r0, {r0, r1} /* restore r0 and r1 */ 1631.1Sthorpej 1641.1Sthorpej /* OK, the machine state should be identical now to that when */ 1651.1Sthorpej /* OFW fielded the interrupt. So just fall through... */ 1661.1Sthorpej 1671.1Sthorpej sub lr, lr, #0x00000004 /* Adjust the lr */ 1681.1Sthorpej 1691.1Sthorpej PUSHFRAMEINSVC /* Push an interrupt frame */ 1701.1Sthorpej 1711.1Sthorpej /* 1721.1Sthorpej * Can't field this interrupt now if priority is _SPL_CLOCK 1731.1Sthorpej * or higher. For now, we'll just ignore the interrupt. 1741.1Sthorpej * Soon, we will have to schedule it for later action. 1751.1Sthorpej */ 1761.1Sthorpej ldr r0, Lcurrent_spl_level 1771.1Sthorpej ldr r0, [r0] 1781.1Sthorpej cmp r0, #_SPL_CLOCK 1791.1Sthorpej blt ofwtakeint 1801.1Sthorpej 1811.1Sthorpej PULLFRAMEFROMSVCANDEXIT 1821.1Sthorpej movs pc, lr /* Exit */ 1831.1Sthorpej 1841.1Sthorpej /* 1851.1Sthorpej * Stuff a bit-mask into r8 indicating which interrupts 1861.1Sthorpej * are pending. In our case, that is just the timer0 1871.1Sthorpej * interrupt: (1 << TIMER0). The existing code will take 1881.1Sthorpej * care of invoking that handler and the softint/ast stuff 1891.1Sthorpej * which follows it. 1901.1Sthorpej */ 1911.1Sthorpejofwtakeint: 1921.3Sscw#if defined(COMPAT_15) && defined(EXEC_AOUT) 1931.3Sscw ldr r0, [sp] /* Fetch SPSR */ 1941.3Sscw#endif 1951.3Sscw ENABLE_ALIGNMENT_FAULTS 1961.3Sscw 1971.1Sthorpej mov r8, #0x00000001 /* timer interrupt pending! */ 1981.1Sthorpej mov r8, r8, lsl #IRQ_TIMER0 1991.1Sthorpej 2001.1Sthorpej /* 2011.1Sthorpej * Note that we have entered the IRQ handler. 2021.1Sthorpej * We are in SVC mode so we cannot use the processor mode 2031.1Sthorpej * to determine if we are in an IRQ. Instead we will count the 2041.1Sthorpej * each time the interrupt handler is nested. 2051.1Sthorpej */ 2061.1Sthorpej 2071.1Sthorpej ldr r0, Lcurrent_intr_depth 2081.1Sthorpej ldr r1, [r0] 2091.1Sthorpej add r1, r1, #1 2101.1Sthorpej str r1, [r0] 2111.1Sthorpej 2121.1Sthorpej /* Block the current requested interrupts */ 2131.1Sthorpej ldr r1, Ldisabled_mask 2141.1Sthorpej ldr r0, [r1] 2151.1Sthorpej stmfd sp!, {r0} 2161.1Sthorpej orr r0, r0, r8 2171.1Sthorpej 2181.1Sthorpej /* 2191.1Sthorpej * Need to block all interrupts at the IPL or lower for 2201.1Sthorpej * all asserted interrupts. 2211.1Sthorpej * This basically emulates hardware interrupt priority levels. 2221.1Sthorpej * Means we need to go through the interrupt mask and for 2231.1Sthorpej * every asserted interrupt we need to mask out all other 2241.1Sthorpej * interrupts at the same or lower IPL. 2251.1Sthorpej * If only we could wait until the main loop but we need to sort 2261.1Sthorpej * this out first so interrupts can be re-enabled. 2271.1Sthorpej * 2281.1Sthorpej * This would benefit from a special ffs type routine 2291.1Sthorpej */ 2301.1Sthorpej 2311.1Sthorpej mov r9, #(_SPL_LEVELS - 1) 2321.1Sthorpej ldr r7, Lspl_masks 2331.1Sthorpej 2341.1SthorpejLfind_highest_ipl: 2351.1Sthorpej ldr r2, [r7, r9, lsl #2] 2361.1Sthorpej tst r8, r2 2371.1Sthorpej subeq r9, r9, #1 2381.1Sthorpej beq Lfind_highest_ipl 2391.1Sthorpej 2401.1Sthorpej /* r9 = SPL level of highest priority interrupt */ 2411.1Sthorpej add r9, r9, #1 2421.1Sthorpej ldr r2, [r7, r9, lsl #2] 2431.1Sthorpej mvn r2, r2 2441.1Sthorpej orr r0, r0, r2 2451.1Sthorpej 2461.1Sthorpej str r0, [r1] 2471.1Sthorpej 2481.1Sthorpej ldr r0, Lcurrent_spl_level 2491.1Sthorpej ldr r1, [r0] 2501.1Sthorpej str r9, [r0] 2511.1Sthorpej stmfd sp!, {r1} 2521.1Sthorpej 2531.1Sthorpej /* Update the irq masks */ 2541.1Sthorpej bl _C_LABEL(irq_setmasks) 2551.1Sthorpej 2561.1Sthorpej mrs r0, cpsr_all /* Enable IRQ's */ 2571.1Sthorpej bic r0, r0, #I32_bit 2581.1Sthorpej msr cpsr_all, r0 2591.1Sthorpej 2601.2Sbjh21 ldr r7, Lirqhandlers 2611.1Sthorpej mov r9, #0x00000001 2621.1Sthorpej 2631.1Sthorpejirqloop: 2641.1Sthorpej /* This would benefit from a special ffs type routine */ 2651.1Sthorpej tst r8, r9 /* Is a bit set ? */ 2661.1Sthorpej beq nextirq /* No ? try next bit */ 2671.1Sthorpej 2681.1Sthorpej ldr r6, [r7] /* Get address of first handler structure */ 2691.1Sthorpej 2701.1Sthorpej teq r6, #0x00000000 /* Do we have a handler */ 2711.1Sthorpej moveq r0, r8 /* IRQ requests as arg 0 */ 2721.1Sthorpej beq _C_LABEL(stray_irqhandler) /* call special handler */ 2731.1Sthorpej 2741.1Sthorpej ldr r0, Lcnt 2751.1Sthorpej ldr r1, [r0, #(V_INTR)] 2761.1Sthorpej add r1, r1, #0x00000001 2771.1Sthorpej str r1, [r0, #(V_INTR)] 2781.1Sthorpej 2791.1Sthorpej/* 2801.1Sthorpej * XXX: Should stats be accumlated for every interrupt routine called 2811.1Sthorpej * or for every physical interrupt that is serviced. 2821.1Sthorpej */ 2831.1Sthorpej 2841.1Sthorpej#ifdef IRQSTATS 2851.1Sthorpej ldr r0, Lintrcnt 2861.1Sthorpej ldr r1, [r6, #(IH_NUM)] 2871.1Sthorpej 2881.1Sthorpej add r0, r0, r1, lsl #2 2891.1Sthorpej ldr r1, [r0] 2901.1Sthorpej add r1, r1, #0x00000001 2911.1Sthorpej str r1, [r0] 2921.1Sthorpej#endif /* IRQSTATS */ 2931.1Sthorpej 2941.1Sthorpejirqchainloop: 2951.1Sthorpej ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 2961.1Sthorpej teq r0, #0x00000000 /* If arg is zero pass stack frame */ 2971.1Sthorpej addeq r0, sp, #8 /* ... stack frame */ 2981.2Sbjh21 mov lr, pc /* return address */ 2991.1Sthorpej ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 3001.1Sthorpej 3011.1Sthorpej teq r0, #0x00000001 /* Was the irq serviced ? */ 3021.1Sthorpej beq irqdone 3031.1Sthorpej 3041.1Sthorpej ldr r6, [r6, #(IH_NEXT)] 3051.1Sthorpej teq r6, #0x00000000 3061.1Sthorpej bne irqchainloop 3071.1Sthorpej 3081.1Sthorpejirqdone: 3091.1Sthorpejnextirq: 3101.1Sthorpej add r7, r7, #0x00000004 /* update pointer to handlers */ 3111.1Sthorpej mov r9, r9, lsl #1 /* move on to next bit */ 3121.1Sthorpej teq r9, #(1 << 24) /* done the last bit ? */ 3131.1Sthorpej bne irqloop /* no - loop back. */ 3141.1Sthorpej 3151.1Sthorpej ldmfd sp!, {r2} 3161.1Sthorpej ldr r1, Lcurrent_spl_level 3171.1Sthorpej str r2, [r1] 3181.1Sthorpej 3191.1Sthorpej /* Restore previous disabled mask */ 3201.1Sthorpej ldmfd sp!, {r2} 3211.1Sthorpej ldr r1, Ldisabled_mask 3221.1Sthorpej str r2, [r1] 3231.1Sthorpej bl _C_LABEL(irq_setmasks) 3241.1Sthorpej 3251.1Sthorpej bl _C_LABEL(dosoftints) /* Handle the soft interrupts */ 3261.1Sthorpej 3271.1Sthorpej /* Kill IRQ's in preparation for exit */ 3281.1Sthorpej mrs r0, cpsr_all 3291.1Sthorpej orr r0, r0, #(I32_bit) 3301.1Sthorpej msr cpsr_all, r0 3311.1Sthorpej 3321.1Sthorpej /* Decrement the nest count */ 3331.1Sthorpej ldr r0, Lcurrent_intr_depth 3341.1Sthorpej ldr r1, [r0] 3351.1Sthorpej sub r1, r1, #1 3361.1Sthorpej str r1, [r0] 3371.1Sthorpej 3381.3Sscw DO_AST_AND_RESTORE_ALIGNMENT_FAULTS 3391.1Sthorpej PULLFRAMEFROMSVCANDEXIT 3401.1Sthorpej movs pc, lr /* Exit */ 3411.1Sthorpej 3421.1SthorpejLspl_mask: 3431.1Sthorpej .word _C_LABEL(spl_mask) /* irq's allowed at current spl level */ 3441.1Sthorpej 3451.1SthorpejLcurrent_mask: 3461.1Sthorpej .word _C_LABEL(current_mask) /* irq's that are usable */ 3471.1Sthorpej 3481.1Sthorpej 3491.1SthorpejENTRY(irq_setmasks) 3501.1Sthorpej /* Do nothing */ 3511.1Sthorpej mov pc, lr 3521.1Sthorpej 3531.1Sthorpej 3541.1SthorpejLcnt: 3551.1Sthorpej .word _C_LABEL(uvmexp) 3561.1Sthorpej 3571.1SthorpejLintrcnt: 3581.1Sthorpej .word _C_LABEL(intrcnt) 3591.1Sthorpej 3601.1Sthorpej 3611.1SthorpejLirqhandlers: 3621.1Sthorpej .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 3631.1Sthorpej 3641.1Sthorpej .text 3651.1Sthorpej .global _C_LABEL(dotickgrovelling) 3661.1Sthorpej 3671.1Sthorpej/* 3681.1Sthorpej * Do magic to cause OFW to call our irq_entry 3691.1Sthorpej * routine when it returns from its tick-handling. 3701.1Sthorpej * 3711.1Sthorpej * This consists of two sub-tasks: 3721.1Sthorpej * - save some machine state in ofw_ticktmp 3731.1Sthorpej * - punch some new machine state into the 3741.1Sthorpej * OFW-supplied frame 3751.1Sthorpej * 3761.1Sthorpej * We are running in the IRQ frame, with 3771.1Sthorpej * interrupts disabled. 3781.1Sthorpej * 3791.1Sthorpej * r0 - base of saved OFW interrupt frame, which 3801.1Sthorpej * has the following format: 3811.1Sthorpej * 3821.1Sthorpej * pc // interrupted instruction 3831.1Sthorpej * lr // lr of interrupted context 3841.1Sthorpej * sp // sp of interrupted context 3851.1Sthorpej * r12 3861.1Sthorpej * ... // non-banked register values 3871.1Sthorpej * ... // of interrupted context 3881.1Sthorpej * r0 3891.1Sthorpej * spsr // psr of interrupted context 3901.1Sthorpej * 3911.1Sthorpej */ 3921.1Sthorpej 3931.1Sthorpej_C_LABEL(dotickgrovelling): 3941.1Sthorpej /*assert((cpsr & PSR_MODE) == PSR_IRQ32_MODE);*/ 3951.1Sthorpej 3961.1Sthorpej stmfd sp!, {r1-r5} /* scratch registers r1-r5 */ 3971.1Sthorpej 3981.1Sthorpej /* 3991.1Sthorpej * Sub-task 1: 4001.1Sthorpej * 4011.1Sthorpej * Our irq_entry routine needs to re-construct 4021.1Sthorpej * the state of the machine at the time OFW 4031.1Sthorpej * fielded the interrupt, so that we can use 4041.1Sthorpej * the rest of the standard interrupt-handling 4051.1Sthorpej * code. Specifically, irq_entry needs to get 4061.1Sthorpej * at the following machine state: 4071.1Sthorpej * 4081.1Sthorpej * pc // interrupted instruction 4091.1Sthorpej * lr_usr 4101.1Sthorpej * sp_usr 4111.1Sthorpej * r0-r12 // the non-banked registers 4121.1Sthorpej * // at the time of interruption 4131.1Sthorpej * spsr // cpsr of interrupted context 4141.1Sthorpej * 4151.1Sthorpej * The non-banked registers will be valid at the 4161.1Sthorpej * time irq_entry is called, but the other values 4171.1Sthorpej * will not be. We must save them here, in the 4181.1Sthorpej * ofw_ticktmp storage block. We also save r0 4191.1Sthorpej * and r1 so that we have some free registers 4201.1Sthorpej * when it's time to do the re-construction. 4211.1Sthorpej * 4221.1Sthorpej * Note that interrupts are not enabled before 4231.1Sthorpej * irq_entry is entered, so we don't have to 4241.1Sthorpej * worry about ofw_ticktmp getting clobbered. 4251.1Sthorpej */ 4261.1Sthorpej ldr r1, Lofw_ticktmp /* r1 points to ofw_ticktmp[0] */ 4271.1Sthorpej 4281.1Sthorpej ldr r2, [r0, #0] /* ofwframe[0] is spsr */ 4291.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[0] */ 4301.1Sthorpej 4311.1Sthorpej ldr r2, [r0, #(4*1)] /* ofwframe[1] is saved r0 */ 4321.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[1] */ 4331.1Sthorpej 4341.1Sthorpej ldr r2, [r0, #(4*2)] /* ofwframe[2] is saved r1 */ 4351.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[2] */ 4361.1Sthorpej 4371.1Sthorpej stmia r1, {sp, lr}^ /* put {sp,lr}_usr in ofw_ticktmp[3,4]; */ 4381.1Sthorpej /* the user registers are still valid */ 4391.1Sthorpej /* because we haven't left IRQ mode */ 4401.1Sthorpej add r1, r1, #(4*2) /* previous instruction can't writeback */ 4411.1Sthorpej /* this one can't use banked registers */ 4421.1Sthorpej 4431.1Sthorpej ldr r2, [r0, #(4*16)] /* ofwframe[16] is pc */ 4441.1Sthorpej stmia r1!, {r2} /* put it in ofw_ticktmp[5] */ 4451.1Sthorpej 4461.1Sthorpej 4471.1Sthorpej /* 4481.1Sthorpej * Sub-task 2: 4491.1Sthorpej * 4501.1Sthorpej * Diddle the OFW-supplied frame such that 4511.1Sthorpej * control passes to irq_entry when OFW does 4521.1Sthorpej * its return from interrupt. There are 4 4531.1Sthorpej * fields in that frame that we need to plug: 4541.1Sthorpej * 4551.1Sthorpej * pc // gets irq_entry 4561.1Sthorpej * lr // gets lr_svc 4571.1Sthorpej * sp // gets sp_svc 4581.1Sthorpej * spsr // gets (I32_bit | PSR_SVC32_MODE) 4591.1Sthorpej * 4601.1Sthorpej */ 4611.1Sthorpej mov r1, #(I32_bit | PSR_SVC32_MODE) 4621.1Sthorpej str r1, [r0, #0] /* plug spsr */ 4631.1Sthorpej 4641.1Sthorpej /* Sneak into SVC mode to get sp and lr */ 4651.1Sthorpej mrs r3, cpsr_all 4661.1Sthorpej bic r3, r3, #(PSR_MODE) 4671.1Sthorpej orr r3, r3, #(PSR_SVC32_MODE) 4681.1Sthorpej msr cpsr_all, r3 4691.1Sthorpej mov r4, lr /* snarf lr_svc */ 4701.1Sthorpej mov r5, sp /* snarf sp_svc */ 4711.1Sthorpej bic r3, r3, #(PSR_MODE) 4721.1Sthorpej orr r3, r3, #(PSR_IRQ32_MODE) 4731.1Sthorpej msr cpsr_all, r3 4741.1Sthorpej str r5, [r0, #(4*14)] /* plug sp */ 4751.1Sthorpej str r4, [r0, #(4*15)] /* plug lr */ 4761.1Sthorpej 4771.2Sbjh21 ldr r1, Lirq_entry 4781.1Sthorpej str r1, [r0, #(4*16)] /* plug pc */ 4791.1Sthorpej 4801.1Sthorpej ldmfd sp!, {r1-r5} 4811.1Sthorpej mov pc, lr 4821.1Sthorpej 4831.1Sthorpej 4841.1Sthorpej .bss 4851.1Sthorpej .align 0 4861.1Sthorpej 4871.1Sthorpej_C_LABEL(ofw_ticktmp): 4881.1Sthorpej .space 4 * 6 /* temporary storage for 6 words of machine state */ 4891.1Sthorpej 4901.1Sthorpejofwirqstk: /* hack */ 4911.1Sthorpej .space 4096 4921.1Sthorpej 4931.1Sthorpej#ifdef IRQSTATS 4941.1Sthorpej/* These symbols are used by vmstat */ 4951.1Sthorpej 4961.1Sthorpej .text 4971.1Sthorpej .global _C_LABEL(_intrnames) 4981.1Sthorpej_C_LABEL(_intrnames): 4991.1Sthorpej .word _C_LABEL(intrnames) 5001.1Sthorpej 5011.1Sthorpej .data 5021.1Sthorpej 5031.1Sthorpej .globl _C_LABEL(intrnames), _C_LABEL(eintrnames), _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt) 5041.1Sthorpej_C_LABEL(intrnames): 5051.1Sthorpej .asciz "interrupt 0 " 5061.1Sthorpej .asciz "interrupt 1 " 5071.1Sthorpej .asciz "interrupt 2 " 5081.1Sthorpej .asciz "interrupt 3 " 5091.1Sthorpej .asciz "interrupt 4 " 5101.1Sthorpej .asciz "interrupt 5 " 5111.1Sthorpej .asciz "interrupt 6 " 5121.1Sthorpej .asciz "interrupt 7 " 5131.1Sthorpej .asciz "interrupt 8 " 5141.1Sthorpej .asciz "interrupt 9 " 5151.1Sthorpej .asciz "interrupt 10 " 5161.1Sthorpej .asciz "interrupt 11 " 5171.1Sthorpej .asciz "interrupt 12 " 5181.1Sthorpej .asciz "interrupt 13 " 5191.1Sthorpej .asciz "interrupt 14 " 5201.1Sthorpej .asciz "interrupt 15 " 5211.1Sthorpej .asciz "interrupt 16 " 5221.1Sthorpej .asciz "interrupt 17 " 5231.1Sthorpej .asciz "interrupt 18 " 5241.1Sthorpej .asciz "interrupt 19 " 5251.1Sthorpej .asciz "interrupt 20 " 5261.1Sthorpej .asciz "interrupt 21 " 5271.1Sthorpej .asciz "interrupt 22 " 5281.1Sthorpej .asciz "interrupt 23 " 5291.1Sthorpej .asciz "interrupt 24 " 5301.1Sthorpej .asciz "interrupt 25 " 5311.1Sthorpej .asciz "interrupt 26 " 5321.1Sthorpej .asciz "interrupt 27 " 5331.1Sthorpej .asciz "interrupt 28 " 5341.1Sthorpej .asciz "interrupt 29 " 5351.1Sthorpej .asciz "interrupt 30 " 5361.1Sthorpej .asciz "interrupt 31 " 5371.1Sthorpej 5381.1Sthorpej_C_LABEL(sintrnames): 5391.1Sthorpej .asciz "softclock " 5401.1Sthorpej .asciz "softnet " 5411.1Sthorpej .asciz "softserial " 5421.1Sthorpej .asciz "softintr 3 " 5431.1Sthorpej .asciz "softintr 4 " 5441.1Sthorpej .asciz "softintr 5 " 5451.1Sthorpej .asciz "softintr 6 " 5461.1Sthorpej .asciz "softintr 7 " 5471.1Sthorpej .asciz "softintr 8 " 5481.1Sthorpej .asciz "softintr 9 " 5491.1Sthorpej .asciz "softintr 10 " 5501.1Sthorpej .asciz "softintr 11 " 5511.1Sthorpej .asciz "softintr 12 " 5521.1Sthorpej .asciz "softintr 13 " 5531.1Sthorpej .asciz "softintr 14 " 5541.1Sthorpej .asciz "softintr 15 " 5551.1Sthorpej .asciz "softintr 16 " 5561.1Sthorpej .asciz "softintr 17 " 5571.1Sthorpej .asciz "softintr 18 " 5581.1Sthorpej .asciz "softintr 19 " 5591.1Sthorpej .asciz "softintr 20 " 5601.1Sthorpej .asciz "softintr 21 " 5611.1Sthorpej .asciz "softintr 22 " 5621.1Sthorpej .asciz "softintr 23 " 5631.1Sthorpej .asciz "softintr 24 " 5641.1Sthorpej .asciz "softintr 25 " 5651.1Sthorpej .asciz "softintr 26 " 5661.1Sthorpej .asciz "softintr 27 " 5671.1Sthorpej .asciz "softintr 28 " 5681.1Sthorpej .asciz "softintr 29 " 5691.1Sthorpej .asciz "softintr 30 " 5701.1Sthorpej .asciz "softintr 31 " 5711.1Sthorpej_C_LABEL(eintrnames): 5721.1Sthorpej 5731.1Sthorpej .bss 5741.1Sthorpej .align 0 5751.1Sthorpej_C_LABEL(intrcnt): 5761.1Sthorpej .space 32*4 /* XXX Should be linked to number of interrupts */ 5771.1Sthorpej 5781.1Sthorpej_C_LABEL(sintrcnt): 5791.1Sthorpej .space 32*4 /* XXX Should be linked to number of interrupts */ 5801.1Sthorpej_C_LABEL(eintrcnt): 5811.1Sthorpej 5821.1Sthorpej#else /* IRQSTATS */ 5831.1Sthorpej/* Dummy entries to keep vmstat happy */ 5841.1Sthorpej 5851.1Sthorpej .text 5861.1Sthorpej .globl _C_LABEL(intrnames), _C_LABEL(eintrnames), _C_LABEL(intrcnt), _C_LABEL(eintrcnt) 5871.1Sthorpej_C_LABEL(intrnames): 5881.1Sthorpej .long 0 5891.1Sthorpej_C_LABEL(eintrnames): 5901.1Sthorpej 5911.1Sthorpej_C_LABEL(intrcnt): 5921.1Sthorpej .long 0 5931.1Sthorpej_C_LABEL(eintrcnt): 5941.1Sthorpej#endif /* IRQSTATS */ 595