1*5e6a531eSskrll/* $NetBSD: isa_irq.S,v 1.18 2020/11/21 19:58:11 skrll Exp $ */ 280675955Sthorpej 380675955Sthorpej/* 480675955Sthorpej * Copyright 1997 580675955Sthorpej * Digital Equipment Corporation. All rights reserved. 680675955Sthorpej * 780675955Sthorpej * This software is furnished under license and may be used and 880675955Sthorpej * copied only in accordance with the following terms and conditions. 980675955Sthorpej * Subject to these conditions, you may download, copy, install, 1080675955Sthorpej * use, modify and distribute this software in source and/or binary 1180675955Sthorpej * form. No title or ownership is transferred hereby. 1280675955Sthorpej * 1380675955Sthorpej * 1) Any source code used, modified or distributed must reproduce 1480675955Sthorpej * and retain this copyright notice and list of conditions as 1580675955Sthorpej * they appear in the source file. 1680675955Sthorpej * 1780675955Sthorpej * 2) No right is granted to use any trade name, trademark, or logo of 1880675955Sthorpej * Digital Equipment Corporation. Neither the "Digital Equipment 1980675955Sthorpej * Corporation" name nor any trademark or logo of Digital Equipment 2080675955Sthorpej * Corporation may be used to endorse or promote products derived 2180675955Sthorpej * from this software without the prior written permission of 2280675955Sthorpej * Digital Equipment Corporation. 2380675955Sthorpej * 2480675955Sthorpej * 3) This software is provided "AS-IS" and any express or implied 2580675955Sthorpej * warranties, including but not limited to, any implied warranties 2680675955Sthorpej * of merchantability, fitness for a particular purpose, or 2780675955Sthorpej * non-infringement are disclaimed. In no event shall DIGITAL be 2880675955Sthorpej * liable for any damages whatsoever, and in particular, DIGITAL 2980675955Sthorpej * shall not be liable for special, indirect, consequential, or 3080675955Sthorpej * incidental damages or damages for lost profits, loss of 3180675955Sthorpej * revenue or loss of use, whether such damages arise in contract, 3280675955Sthorpej * negligence, tort, under statute, in equity, at law or otherwise, 3380675955Sthorpej * even if advised of the possibility of such damage. 3480675955Sthorpej */ 3580675955Sthorpej 3680675955Sthorpej/* 3780675955Sthorpej * Copyright (c) 1994-1998 Mark Brinicombe. 3880675955Sthorpej * Copyright (c) 1994 Brini. 3980675955Sthorpej * All rights reserved. 4080675955Sthorpej * 4180675955Sthorpej * This code is derived from software written for Brini by Mark Brinicombe 4280675955Sthorpej * 4380675955Sthorpej * Redistribution and use in source and binary forms, with or without 4480675955Sthorpej * modification, are permitted provided that the following conditions 4580675955Sthorpej * are met: 4680675955Sthorpej * 1. Redistributions of source code must retain the above copyright 4780675955Sthorpej * notice, this list of conditions and the following disclaimer. 4880675955Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 4980675955Sthorpej * notice, this list of conditions and the following disclaimer in the 5080675955Sthorpej * documentation and/or other materials provided with the distribution. 5180675955Sthorpej * 3. All advertising materials mentioning features or use of this software 5280675955Sthorpej * must display the following acknowledgement: 5380675955Sthorpej * This product includes software developed by Mark Brinicombe 5480675955Sthorpej * for the NetBSD Project. 5580675955Sthorpej * 4. The name of the company nor the name of the author may be used to 5680675955Sthorpej * endorse or promote products derived from this software without specific 5780675955Sthorpej * prior written permission. 5880675955Sthorpej * 5980675955Sthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 6080675955Sthorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 6180675955Sthorpej * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 6280675955Sthorpej * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 6380675955Sthorpej * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 6480675955Sthorpej * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 6580675955Sthorpej * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 6680675955Sthorpej * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 6780675955Sthorpej * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 6880675955Sthorpej * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6980675955Sthorpej * 7080675955Sthorpej * from: irq.S 7180675955Sthorpej * 7280675955Sthorpej * Low level irq and fiq handlers 7380675955Sthorpej * 7480675955Sthorpej * Created : 27/09/94 7580675955Sthorpej */ 7680675955Sthorpej 7780675955Sthorpej#include "assym.h" 7880675955Sthorpej#include <machine/asm.h> 7980675955Sthorpej#include <machine/cpu.h> 8080675955Sthorpej#include <machine/frame.h> 8180675955Sthorpej#include <dev/isa/isareg.h> 8280675955Sthorpej#include <shark/isa/icu.h> 8380675955Sthorpej#include <machine/irqhandler.h> 8480675955Sthorpej 8580675955Sthorpej .text 8680675955Sthorpej .align 0 8780675955Sthorpej 8880675955Sthorpej/* 8980675955Sthorpej * 9080675955Sthorpej * irq_entry 9180675955Sthorpej * 9280675955Sthorpej * Main entry point for the IRQ vector 9380675955Sthorpej * 9480675955Sthorpej * This function reads the irq request bits in the IOMD registers 9580675955Sthorpej * IRQRQA, IRQRQB and DMARQ 9680675955Sthorpej * It then calls an installed handler for each bit that is set. 9780675955Sthorpej * The function stray_irqhandler is called if a handler is not defined 9880675955Sthorpej * for a particular interrupt. 9980675955Sthorpej * If a interrupt handler is found then it is called with r0 containing 10080675955Sthorpej * the argument defined in the handler structure. If the field ih_arg 10180675955Sthorpej * is zero then a pointer to the IRQ frame on the stack is passed instead. 10280675955Sthorpej */ 10380675955Sthorpej 104825088edSmatt.Ldisabled_mask: 10580675955Sthorpej .word _C_LABEL(disabled_mask) 10680675955Sthorpej 107825088edSmatt.Lvam_io_data: 10880675955Sthorpej .word _C_LABEL(isa_io_bs_tag) 10980675955Sthorpej 110825088edSmatt.Lspl_masks: 11180675955Sthorpej .word _C_LABEL(spl_masks) 11280675955Sthorpej 11380675955Sthorpej/* 11480675955Sthorpej * Register usage 11580675955Sthorpej * 11680675955Sthorpej * r6 - Address of current handler 117*5e6a531eSskrll * r7 - Pointer to handler pointer list 11880675955Sthorpej * r8 - Current IRQ requests. 11980675955Sthorpej * r9 - Used to count through possible IRQ bits. 12080675955Sthorpej * r10 - Base address of IOMD 12180675955Sthorpej */ 12280675955Sthorpej 12380675955Sthorpej/* Some documentation is in isa_machdep.c */ 12480675955SthorpejASENTRY_NP(irq_entry) 12580675955Sthorpej sub lr, lr, #0x00000004 /* Adjust the lr */ 12680675955Sthorpej 12780675955Sthorpej PUSHFRAMEINSVC /* Push an interrupt frame */ 128*5e6a531eSskrll ENABLE_ALIGNMENT_FAULTS /* puts cur{cpu,lwp} in r4/r5 */ 12980675955Sthorpej 13080675955Sthorpej /* Load r8 with the ISA 8259 irqs */ 13180675955Sthorpej /* r8 <- irq's pending [15:0] */ 13280675955Sthorpej 13380675955Sthorpej /* address of 8259 #1 */ 134825088edSmatt ldr r0, .Lvam_io_data 13580675955Sthorpej ldr r0, [r0] 13680675955Sthorpej ldrb r8, [r0, #IO_ICU1] /* ocw3 = irr */ 13780675955Sthorpej 13880675955Sthorpej /* clear the IRR bits that are currently masked. */ 139825088edSmatt ldr r2, .Li8259_mask 14080675955Sthorpej ldr r2, [r2] 14180675955Sthorpej mvn r2, r2 /* disabled -> enabled */ 14280675955Sthorpej 14380675955Sthorpej /* address of 8259 #2 */ 14480675955Sthorpej tst r2, #(1 << IRQ_SLAVE) /* if slave is enabled */ 14580675955Sthorpej tstne r8, #(1 << IRQ_SLAVE) /* anything from slave? */ 146029a1f3bSmatt ldrbne r1, [r0, #IO_ICU2] /* ocw3 = irr */ 14780675955Sthorpej orrne r8, r8, r1, lsl #8 14880675955Sthorpej 14980675955Sthorpej and r8, r8, r2 /* clear disabled */ 15080675955Sthorpej 15180675955Sthorpej /* clear IRQ 2, which is only used for slave 8259 */ 15280675955Sthorpej bic r8, r8, #(1 << IRQ_SLAVE) 15380675955Sthorpej 15480675955Sthorpej /* 15580675955Sthorpej * Note that we have entered the IRQ handler. 15680675955Sthorpej * We are in SVC mode so we cannot use the processor mode 15780675955Sthorpej * to determine if we are in an IRQ. Instead we will count the 15880675955Sthorpej * each time the interrupt handler is nested. 15980675955Sthorpej */ 16080675955Sthorpej 161825088edSmatt ldr r1, [r4, #CI_INTR_DEPTH] 16280675955Sthorpej add r1, r1, #1 163825088edSmatt str r1, [r4, #CI_INTR_DEPTH] 16480675955Sthorpej 16580675955Sthorpej /* Block the current requested interrupts */ 16680675955Sthorpej 167825088edSmatt ldr r1, .Ldisabled_mask 16880675955Sthorpej ldr r0, [r1] 16980675955Sthorpej stmfd sp!, {r0} 17080675955Sthorpej orr r0, r0, r8 17180675955Sthorpej 17280675955Sthorpej /* 17380675955Sthorpej * Need to block all interrupts at the IPL or lower for 17480675955Sthorpej * all asserted interrupts. 17580675955Sthorpej * This basically emulates hardware interrupt priority levels. 17680675955Sthorpej * Means we need to go through the interrupt mask and for 17780675955Sthorpej * every asserted interrupt we need to mask out all other 17880675955Sthorpej * interrupts at the same or lower IPL. 17980675955Sthorpej * If only we could wait until the main loop but we need to sort 18080675955Sthorpej * this out first so interrupts can be re-enabled. 18180675955Sthorpej * 18280675955Sthorpej * This would benefit from a special ffs type routine 18380675955Sthorpej */ 18480675955Sthorpej 185825088edSmatt mov r9, #(NIPL - 1) 186*5e6a531eSskrll ldr r7, .Lspl_masks 18780675955Sthorpej 188825088edSmatt.Lfind_highest_ipl: 189*5e6a531eSskrll ldr r2, [r7, r9, lsl #2] 19080675955Sthorpej tst r8, r2 19180675955Sthorpej subeq r9, r9, #1 192825088edSmatt beq .Lfind_highest_ipl 19380675955Sthorpej 19480675955Sthorpej /* r9 = SPL level of highest priority interrupt */ 19580675955Sthorpej add r9, r9, #1 196*5e6a531eSskrll ldr r2, [r7, r9, lsl #2] 19780675955Sthorpej mvn r2, r2 19880675955Sthorpej orr r0, r0, r2 19980675955Sthorpej 20080675955Sthorpej str r0, [r1] 20180675955Sthorpej 202825088edSmatt ldr r1, [r4, #CI_CPL] 203825088edSmatt str r9, [r4, #CI_CPL] 20480675955Sthorpej stmfd sp!, {r1} 20580675955Sthorpej 20680675955Sthorpej /* Update the IOMD irq masks */ 20780675955Sthorpej bl _C_LABEL(irq_setmasks) 20880675955Sthorpej 2098b058f85Sjoerg mrs r0, cpsr /* Enable IRQ's */ 21080675955Sthorpej bic r0, r0, #I32_bit 21180675955Sthorpej msr cpsr_all, r0 21280675955Sthorpej 213*5e6a531eSskrll ldr r7, .Lirqhandlers 21480675955Sthorpej mov r9, #0x00000001 21580675955Sthorpej 21680675955Sthorpejirqloop: 21780675955Sthorpej /* This would benefit from a special ffs type routine */ 21880675955Sthorpej tst r8, r9 /* Is a bit set ? */ 21980675955Sthorpej beq nextirq /* No ? try next bit */ 22080675955Sthorpej 221*5e6a531eSskrll ldr r6, [r7] /* Get address of first handler structure */ 22280675955Sthorpej 22380675955Sthorpej teq r6, #0x00000000 /* Do we have a handler */ 22480675955Sthorpej moveq r0, r8 /* IRQ requests as arg 0 */ 22580675955Sthorpej beq _C_LABEL(stray_irqhandler) /* call special handler */ 22680675955Sthorpej 2276a66466fSmatt ldr r0, [r4, #(CI_CC_NINTR)] 2286a66466fSmatt ldr r1, [r4, #(CI_CC_NINTR+4)] 2296a66466fSmatt adds r0, r0, #0x00000001 2306a66466fSmatt adc r1, r1, #0x00000000 2316a66466fSmatt str r0, [r4, #(CI_CC_NINTR)] 2326a66466fSmatt ldr r1, [r4, #(CI_CC_NINTR+4)] 23380675955Sthorpej 23480675955Sthorpejirqchainloop: 23580675955Sthorpej ldr r0, [r6, #(IH_ARG)] /* Get argument pointer */ 23680675955Sthorpej teq r0, #0x00000000 /* If arg is zero pass stack frame */ 23780675955Sthorpej addeq r0, sp, #8 /* ... stack frame */ 2382c6d199dSmatt 239d599df95Sbjh21 mov lr, pc /* return address */ 24080675955Sthorpej ldr pc, [r6, #(IH_FUNC)] /* Call handler */ 24180675955Sthorpej 24280675955Sthorpej teq r0, #0x00000001 /* Was the irq serviced ? */ 24380675955Sthorpej beq irqdone 24480675955Sthorpej 24580675955Sthorpej ldr r6, [r6, #(IH_NEXT)] 24680675955Sthorpej teq r6, #0x00000000 24780675955Sthorpej bne irqchainloop 248d471ccf3Smatt b nextirq 24980675955Sthorpej 25080675955Sthorpejirqdone: 251d471ccf3Smatt add r3, r6, #IH_EV_COUNT /* get address of ih's ev_count */ 252d471ccf3Smatt ldmia r3, {r1-r2} /* load ev_count */ 253d471ccf3Smatt adds r1, r1, #0x00000001 /* 64bit incr (lo) */ 254d471ccf3Smatt adc r2, r2, #0x00000000 /* 64bit incr (hi) */ 255d471ccf3Smatt stmia r3, {r1-r2} /* store ev_count */ 256d471ccf3Smatt 25780675955Sthorpejnextirq: 258*5e6a531eSskrll add r7, r7, #0x00000004 /* update pointer to handlers */ 25980675955Sthorpej mov r9, r9, lsl #1 /* move on to next bit */ 26080675955Sthorpej teq r9, #(1 << 16) /* done the last bit ? */ 26180675955Sthorpej bne irqloop /* no - loop back. */ 26280675955Sthorpej 26380675955Sthorpej ldmfd sp!, {r2} 264825088edSmatt str r2, [r4, #CI_CPL] 26580675955Sthorpej 26680675955Sthorpej /* Restore previous disabled mask */ 26780675955Sthorpej ldmfd sp!, {r2} 268825088edSmatt ldr r1, .Ldisabled_mask 26980675955Sthorpej str r2, [r1] 27080675955Sthorpej bl _C_LABEL(irq_setmasks) 27180675955Sthorpej 27280675955Sthorpej /* Kill IRQ's in preparation for exit */ 2738b058f85Sjoerg mrs r0, cpsr 27480675955Sthorpej orr r0, r0, #(I32_bit) 27580675955Sthorpej msr cpsr_all, r0 27680675955Sthorpej 27780675955Sthorpej /* Decrement the nest count */ 278825088edSmatt ldr r1, [r4, #CI_INTR_DEPTH] 27980675955Sthorpej sub r1, r1, #1 280825088edSmatt str r1, [r4, #CI_INTR_DEPTH] 28180675955Sthorpej 282165d4e6dSthorpej LOCK_CAS_CHECK 283165d4e6dSthorpej 284754f153bSscw DO_AST_AND_RESTORE_ALIGNMENT_FAULTS 28580675955Sthorpej PULLFRAMEFROMSVCANDEXIT 28680675955Sthorpej 28780675955Sthorpej /* NOT REACHED */ 28880675955Sthorpej b . - 8 28980675955Sthorpej 290825088edSmatt.Lcurrent_mask: 29180675955Sthorpej .word _C_LABEL(current_mask) /* irq's that are usable */ 29280675955Sthorpej 293825088edSmatt.Lcpu_info_store: 294825088edSmatt .word _C_LABEL(cpu_info_store) 295825088edSmatt 296165d4e6dSthorpejLOCK_CAS_CHECK_LOCALS 297165d4e6dSthorpej 298754f153bSscwAST_ALIGNMENT_FAULT_LOCALS 299754f153bSscw 300754f153bSscw 30180675955SthorpejENTRY(irq_setmasks) 30280675955Sthorpej /* Disable interrupts */ 3038b058f85Sjoerg mrs r3, cpsr 30480675955Sthorpej orr r1, r3, #(I32_bit) 30580675955Sthorpej msr cpsr_all, r1 30680675955Sthorpej 30780675955Sthorpej /* Calculate interrupt mask */ 308825088edSmatt ldr r1, .Lcurrent_mask /* All the enabled interrupts */ 30980675955Sthorpej ldrh r1, [r1] /* get hardware bits of mask */ 31080675955Sthorpej/* .word 0xe0d110b0 */ /* hand-assembled ldrh r1, [r1] */ 311825088edSmatt ldr r0, .Lspl_masks 312825088edSmatt ldr r2, .Lcpu_info_store 313825088edSmatt ldr r2, [r2, #CI_CPL] 3145c47006eStsutsui ldr r2, [r0, r2, lsl #2] 31580675955Sthorpej and r1, r1, r2 316825088edSmatt ldr r2, .Ldisabled_mask /* Block due to active interrupts */ 31780675955Sthorpej ldr r2, [r2] 31880675955Sthorpej bic r1, r1, r2 31980675955Sthorpej 32080675955Sthorpej /* since 8259's are so slow to access, this code does everything 32180675955Sthorpej possible to avoid them */ 32280675955Sthorpej 32380675955Sthorpej /* get current mask: these are the bits */ 324825088edSmatt ldr r0, .Li8259_mask 32580675955Sthorpej ldr r2, [r0] 32680675955Sthorpej /* r2 = 0000.0000.0000.0000.ZZZZ.ZZZZ.ZZZZ.ZZZZ */ 32780675955Sthorpej 32880675955Sthorpej /* see if there's anything enabled on 8259 #2 */ 32980675955Sthorpej tst r1, #0xff00 33080675955Sthorpej 33180675955Sthorpej biceq r1, r1, #(1 << IRQ_SLAVE) /* no, so disable it */ 33280675955Sthorpej orrne r1, r1, #(1 << IRQ_SLAVE) /* yes, so enable it */ 33380675955Sthorpej /* eq => r1 = 0000.0000.0000.0000.0000.0000.MMMM.M0MM 33480675955Sthorpej ne => r1 = 0000.0000.0000.0000.MMMM.MMMM.MMMM.M1MM */ 33580675955Sthorpej 33680675955Sthorpej /* 8259 bit high => disable */ 33780675955Sthorpej mvn r1, r1 33880675955Sthorpej /* eq => r1 = 1111.1111.1111.1111.1111.1111.YYYY.Y1YY 33980675955Sthorpej ne => r1 = 1111.1111.1111.1111.YYYY.YYYY.YYYY.Y0YY 34080675955Sthorpej (for each bit position Y = !M) */ 34180675955Sthorpej 34280675955Sthorpej orreq r1, r2, r1, lsl #16 34380675955Sthorpej /* eq => r1 = 1111.1111.YYYY.Y1YY.ZZZZ.ZZZZ.ZZZZ.ZZZZ 34480675955Sthorpej ne => r1 = 1111.1111.1111.1111.YYYY.YYYY.YYYY.Y0YY */ 34580675955Sthorpej orreq r1, r1, #0x000000FF 34680675955Sthorpej /* eq => r1 = 1111.1111.YYYY.Y1YY.ZZZZ.ZZZZ.1111.1111 34780675955Sthorpej ne => r1 = 1111.1111.1111.1111.YYYY.YYYY.YYYY.Y0YY */ 34880675955Sthorpej and r1, r1, r1, lsr #16 34980675955Sthorpej /* eq => r1 = 0000.0000.0000.0000.ZZZZ.ZZZZ.YYYY.Y1YY 35080675955Sthorpej ne => r1 = 0000.0000.0000.0000.YYYY.YYYY.YYYY.Y0YY */ 35180675955Sthorpej 35280675955Sthorpej /* if old = new, don't bother to set again. 35380675955Sthorpej fast path to exit, since 8259's are so slow anyway */ 35480675955Sthorpej eors r2, r1, r2 /* which bits are different? */ 35580675955Sthorpej msreq cpsr_all, r3 /* no bits are different, return */ 35680675955Sthorpej moveq pc, lr 35780675955Sthorpej 35880675955Sthorpej /* have to set at least one of the 8259's, store new mask */ 35980675955Sthorpej str r1, [r0] 360825088edSmatt ldr r0, .Lvam_io_data 36180675955Sthorpej ldr r0, [r0] 36280675955Sthorpej 36380675955Sthorpej /* see if there's any change for 8259 #1 (master) */ 36480675955Sthorpej tst r2, #0x00FF /* bottom 8 bits different? */ 365029a1f3bSmatt strbne r1, [r0, #(IO_ICU1 + 1)] /* icu1 / ocw1 */ 36680675955Sthorpej 36780675955Sthorpej /* anything for 8259 #2? */ 36880675955Sthorpej tst r2, #0xFF00 36980675955Sthorpej mov r1, r1, lsr #8 /* next byte */ 370029a1f3bSmatt strbne r1, [r0, #(IO_ICU2 + 1)] /* icu2 / ocw1 */ 37180675955Sthorpej 37280675955Sthorpej /* Restore old cpsr and exit */ 37380675955Sthorpej msr cpsr_all, r3 37480675955Sthorpej mov pc, lr 37580675955Sthorpej 376825088edSmatt.Li8259_mask: 37780675955Sthorpej .word _C_LABEL(i8259_mask) 37880675955Sthorpej 379825088edSmatt.Lirqhandlers: 38080675955Sthorpej .word _C_LABEL(irqhandlers) /* Pointer to array of irqhandlers */ 381