1 /* 2 * linux/arch/mips/dec/ioasic-irq.c 3 * 4 * DEC I/O ASIC interrupts. 5 * 6 * Copyright (c) 2002, 2003 Maciej W. Rozycki 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 */ 13 14 #include <linux/init.h> 15 #include <linux/irq.h> 16 #include <linux/spinlock.h> 17 #include <linux/types.h> 18 19 #include <asm/dec/ioasic.h> 20 #include <asm/dec/ioasic_addrs.h> 21 #include <asm/dec/ioasic_ints.h> 22 23 24 static DEFINE_SPINLOCK(ioasic_lock); 25 26 static int ioasic_irq_base; 27 28 29 static inline void unmask_ioasic_irq(unsigned int irq) 30 { 31 u32 simr; 32 33 simr = ioasic_read(IO_REG_SIMR); 34 simr |= (1 << (irq - ioasic_irq_base)); 35 ioasic_write(IO_REG_SIMR, simr); 36 } 37 38 static inline void mask_ioasic_irq(unsigned int irq) 39 { 40 u32 simr; 41 42 simr = ioasic_read(IO_REG_SIMR); 43 simr &= ~(1 << (irq - ioasic_irq_base)); 44 ioasic_write(IO_REG_SIMR, simr); 45 } 46 47 static inline void clear_ioasic_irq(unsigned int irq) 48 { 49 u32 sir; 50 51 sir = ~(1 << (irq - ioasic_irq_base)); 52 ioasic_write(IO_REG_SIR, sir); 53 } 54 55 static inline void enable_ioasic_irq(unsigned int irq) 56 { 57 unsigned long flags; 58 59 spin_lock_irqsave(&ioasic_lock, flags); 60 unmask_ioasic_irq(irq); 61 spin_unlock_irqrestore(&ioasic_lock, flags); 62 } 63 64 static inline void disable_ioasic_irq(unsigned int irq) 65 { 66 unsigned long flags; 67 68 spin_lock_irqsave(&ioasic_lock, flags); 69 mask_ioasic_irq(irq); 70 spin_unlock_irqrestore(&ioasic_lock, flags); 71 } 72 73 74 static inline unsigned int startup_ioasic_irq(unsigned int irq) 75 { 76 enable_ioasic_irq(irq); 77 return 0; 78 } 79 80 #define shutdown_ioasic_irq disable_ioasic_irq 81 82 static inline void ack_ioasic_irq(unsigned int irq) 83 { 84 spin_lock(&ioasic_lock); 85 mask_ioasic_irq(irq); 86 spin_unlock(&ioasic_lock); 87 fast_iob(); 88 } 89 90 static inline void end_ioasic_irq(unsigned int irq) 91 { 92 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 93 enable_ioasic_irq(irq); 94 } 95 96 static struct hw_interrupt_type ioasic_irq_type = { 97 .typename = "IO-ASIC", 98 .startup = startup_ioasic_irq, 99 .shutdown = shutdown_ioasic_irq, 100 .enable = enable_ioasic_irq, 101 .disable = disable_ioasic_irq, 102 .ack = ack_ioasic_irq, 103 .end = end_ioasic_irq, 104 }; 105 106 107 #define startup_ioasic_dma_irq startup_ioasic_irq 108 109 #define shutdown_ioasic_dma_irq shutdown_ioasic_irq 110 111 #define enable_ioasic_dma_irq enable_ioasic_irq 112 113 #define disable_ioasic_dma_irq disable_ioasic_irq 114 115 #define ack_ioasic_dma_irq ack_ioasic_irq 116 117 static inline void end_ioasic_dma_irq(unsigned int irq) 118 { 119 clear_ioasic_irq(irq); 120 fast_iob(); 121 end_ioasic_irq(irq); 122 } 123 124 static struct hw_interrupt_type ioasic_dma_irq_type = { 125 .typename = "IO-ASIC-DMA", 126 .startup = startup_ioasic_dma_irq, 127 .shutdown = shutdown_ioasic_dma_irq, 128 .enable = enable_ioasic_dma_irq, 129 .disable = disable_ioasic_dma_irq, 130 .ack = ack_ioasic_dma_irq, 131 .end = end_ioasic_dma_irq, 132 }; 133 134 135 void __init init_ioasic_irqs(int base) 136 { 137 int i; 138 139 /* Mask interrupts. */ 140 ioasic_write(IO_REG_SIMR, 0); 141 fast_iob(); 142 143 for (i = base; i < base + IO_INR_DMA; i++) { 144 irq_desc[i].status = IRQ_DISABLED; 145 irq_desc[i].action = 0; 146 irq_desc[i].depth = 1; 147 irq_desc[i].handler = &ioasic_irq_type; 148 } 149 for (; i < base + IO_IRQ_LINES; i++) { 150 irq_desc[i].status = IRQ_DISABLED; 151 irq_desc[i].action = 0; 152 irq_desc[i].depth = 1; 153 irq_desc[i].handler = &ioasic_dma_irq_type; 154 } 155 156 ioasic_irq_base = base; 157 } 158