Commit 896508705561bea24656680cdaf3b4095c4d7473

Authored by Ralf Baechle
1 parent 598c5abad7

MIPS: i8259: Convert IRQ controller lock to raw spinlock.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Showing 3 changed files with 16 additions and 16 deletions Inline Diff

arch/mips/include/asm/i8259.h
1 /* 1 /*
2 * include/asm-mips/i8259.h 2 * include/asm-mips/i8259.h
3 * 3 *
4 * i8259A interrupt definitions. 4 * i8259A interrupt definitions.
5 * 5 *
6 * Copyright (C) 2003 Maciej W. Rozycki 6 * Copyright (C) 2003 Maciej W. Rozycki
7 * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org> 7 * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org>
8 * 8 *
9 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License 10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version. 12 * 2 of the License, or (at your option) any later version.
13 */ 13 */
14 #ifndef _ASM_I8259_H 14 #ifndef _ASM_I8259_H
15 #define _ASM_I8259_H 15 #define _ASM_I8259_H
16 16
17 #include <linux/compiler.h> 17 #include <linux/compiler.h>
18 #include <linux/spinlock.h> 18 #include <linux/spinlock.h>
19 19
20 #include <asm/io.h> 20 #include <asm/io.h>
21 #include <irq.h> 21 #include <irq.h>
22 22
23 /* i8259A PIC registers */ 23 /* i8259A PIC registers */
24 #define PIC_MASTER_CMD 0x20 24 #define PIC_MASTER_CMD 0x20
25 #define PIC_MASTER_IMR 0x21 25 #define PIC_MASTER_IMR 0x21
26 #define PIC_MASTER_ISR PIC_MASTER_CMD 26 #define PIC_MASTER_ISR PIC_MASTER_CMD
27 #define PIC_MASTER_POLL PIC_MASTER_ISR 27 #define PIC_MASTER_POLL PIC_MASTER_ISR
28 #define PIC_MASTER_OCW3 PIC_MASTER_ISR 28 #define PIC_MASTER_OCW3 PIC_MASTER_ISR
29 #define PIC_SLAVE_CMD 0xa0 29 #define PIC_SLAVE_CMD 0xa0
30 #define PIC_SLAVE_IMR 0xa1 30 #define PIC_SLAVE_IMR 0xa1
31 31
32 /* i8259A PIC related value */ 32 /* i8259A PIC related value */
33 #define PIC_CASCADE_IR 2 33 #define PIC_CASCADE_IR 2
34 #define MASTER_ICW4_DEFAULT 0x01 34 #define MASTER_ICW4_DEFAULT 0x01
35 #define SLAVE_ICW4_DEFAULT 0x01 35 #define SLAVE_ICW4_DEFAULT 0x01
36 #define PIC_ICW4_AEOI 2 36 #define PIC_ICW4_AEOI 2
37 37
38 extern spinlock_t i8259A_lock; 38 extern raw_spinlock_t i8259A_lock;
39 39
40 extern int i8259A_irq_pending(unsigned int irq); 40 extern int i8259A_irq_pending(unsigned int irq);
41 extern void make_8259A_irq(unsigned int irq); 41 extern void make_8259A_irq(unsigned int irq);
42 42
43 extern void init_i8259_irqs(void); 43 extern void init_i8259_irqs(void);
44 44
45 /* 45 /*
46 * Do the traditional i8259 interrupt polling thing. This is for the few 46 * Do the traditional i8259 interrupt polling thing. This is for the few
47 * cases where no better interrupt acknowledge method is available and we 47 * cases where no better interrupt acknowledge method is available and we
48 * absolutely must touch the i8259. 48 * absolutely must touch the i8259.
49 */ 49 */
50 static inline int i8259_irq(void) 50 static inline int i8259_irq(void)
51 { 51 {
52 int irq; 52 int irq;
53 53
54 spin_lock(&i8259A_lock); 54 raw_spin_lock(&i8259A_lock);
55 55
56 /* Perform an interrupt acknowledge cycle on controller 1. */ 56 /* Perform an interrupt acknowledge cycle on controller 1. */
57 outb(0x0C, PIC_MASTER_CMD); /* prepare for poll */ 57 outb(0x0C, PIC_MASTER_CMD); /* prepare for poll */
58 irq = inb(PIC_MASTER_CMD) & 7; 58 irq = inb(PIC_MASTER_CMD) & 7;
59 if (irq == PIC_CASCADE_IR) { 59 if (irq == PIC_CASCADE_IR) {
60 /* 60 /*
61 * Interrupt is cascaded so perform interrupt 61 * Interrupt is cascaded so perform interrupt
62 * acknowledge on controller 2. 62 * acknowledge on controller 2.
63 */ 63 */
64 outb(0x0C, PIC_SLAVE_CMD); /* prepare for poll */ 64 outb(0x0C, PIC_SLAVE_CMD); /* prepare for poll */
65 irq = (inb(PIC_SLAVE_CMD) & 7) + 8; 65 irq = (inb(PIC_SLAVE_CMD) & 7) + 8;
66 } 66 }
67 67
68 if (unlikely(irq == 7)) { 68 if (unlikely(irq == 7)) {
69 /* 69 /*
70 * This may be a spurious interrupt. 70 * This may be a spurious interrupt.
71 * 71 *
72 * Read the interrupt status register (ISR). If the most 72 * Read the interrupt status register (ISR). If the most
73 * significant bit is not set then there is no valid 73 * significant bit is not set then there is no valid
74 * interrupt. 74 * interrupt.
75 */ 75 */
76 outb(0x0B, PIC_MASTER_ISR); /* ISR register */ 76 outb(0x0B, PIC_MASTER_ISR); /* ISR register */
77 if(~inb(PIC_MASTER_ISR) & 0x80) 77 if(~inb(PIC_MASTER_ISR) & 0x80)
78 irq = -1; 78 irq = -1;
79 } 79 }
80 80
81 spin_unlock(&i8259A_lock); 81 raw_spin_unlock(&i8259A_lock);
82 82
83 return likely(irq >= 0) ? irq + I8259A_IRQ_BASE : irq; 83 return likely(irq >= 0) ? irq + I8259A_IRQ_BASE : irq;
84 } 84 }
85 85
86 #endif /* _ASM_I8259_H */ 86 #endif /* _ASM_I8259_H */
87 87
arch/mips/kernel/i8259.c
1 /* 1 /*
2 * This file is subject to the terms and conditions of the GNU General Public 2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive 3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details. 4 * for more details.
5 * 5 *
6 * Code to handle x86 style IRQs plus some generic interrupt stuff. 6 * Code to handle x86 style IRQs plus some generic interrupt stuff.
7 * 7 *
8 * Copyright (C) 1992 Linus Torvalds 8 * Copyright (C) 1992 Linus Torvalds
9 * Copyright (C) 1994 - 2000 Ralf Baechle 9 * Copyright (C) 1994 - 2000 Ralf Baechle
10 */ 10 */
11 #include <linux/delay.h> 11 #include <linux/delay.h>
12 #include <linux/init.h> 12 #include <linux/init.h>
13 #include <linux/ioport.h> 13 #include <linux/ioport.h>
14 #include <linux/interrupt.h> 14 #include <linux/interrupt.h>
15 #include <linux/kernel.h> 15 #include <linux/kernel.h>
16 #include <linux/spinlock.h> 16 #include <linux/spinlock.h>
17 #include <linux/sysdev.h> 17 #include <linux/sysdev.h>
18 18
19 #include <asm/i8259.h> 19 #include <asm/i8259.h>
20 #include <asm/io.h> 20 #include <asm/io.h>
21 21
22 /* 22 /*
23 * This is the 'legacy' 8259A Programmable Interrupt Controller, 23 * This is the 'legacy' 8259A Programmable Interrupt Controller,
24 * present in the majority of PC/AT boxes. 24 * present in the majority of PC/AT boxes.
25 * plus some generic x86 specific things if generic specifics makes 25 * plus some generic x86 specific things if generic specifics makes
26 * any sense at all. 26 * any sense at all.
27 * this file should become arch/i386/kernel/irq.c when the old irq.c 27 * this file should become arch/i386/kernel/irq.c when the old irq.c
28 * moves to arch independent land 28 * moves to arch independent land
29 */ 29 */
30 30
31 static int i8259A_auto_eoi = -1; 31 static int i8259A_auto_eoi = -1;
32 DEFINE_SPINLOCK(i8259A_lock); 32 DEFINE_RAW_SPINLOCK(i8259A_lock);
33 static void disable_8259A_irq(unsigned int irq); 33 static void disable_8259A_irq(unsigned int irq);
34 static void enable_8259A_irq(unsigned int irq); 34 static void enable_8259A_irq(unsigned int irq);
35 static void mask_and_ack_8259A(unsigned int irq); 35 static void mask_and_ack_8259A(unsigned int irq);
36 static void init_8259A(int auto_eoi); 36 static void init_8259A(int auto_eoi);
37 37
38 static struct irq_chip i8259A_chip = { 38 static struct irq_chip i8259A_chip = {
39 .name = "XT-PIC", 39 .name = "XT-PIC",
40 .mask = disable_8259A_irq, 40 .mask = disable_8259A_irq,
41 .disable = disable_8259A_irq, 41 .disable = disable_8259A_irq,
42 .unmask = enable_8259A_irq, 42 .unmask = enable_8259A_irq,
43 .mask_ack = mask_and_ack_8259A, 43 .mask_ack = mask_and_ack_8259A,
44 #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF 44 #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
45 .set_affinity = plat_set_irq_affinity, 45 .set_affinity = plat_set_irq_affinity,
46 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ 46 #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
47 }; 47 };
48 48
49 /* 49 /*
50 * 8259A PIC functions to handle ISA devices: 50 * 8259A PIC functions to handle ISA devices:
51 */ 51 */
52 52
53 /* 53 /*
54 * This contains the irq mask for both 8259A irq controllers, 54 * This contains the irq mask for both 8259A irq controllers,
55 */ 55 */
56 static unsigned int cached_irq_mask = 0xffff; 56 static unsigned int cached_irq_mask = 0xffff;
57 57
58 #define cached_master_mask (cached_irq_mask) 58 #define cached_master_mask (cached_irq_mask)
59 #define cached_slave_mask (cached_irq_mask >> 8) 59 #define cached_slave_mask (cached_irq_mask >> 8)
60 60
61 static void disable_8259A_irq(unsigned int irq) 61 static void disable_8259A_irq(unsigned int irq)
62 { 62 {
63 unsigned int mask; 63 unsigned int mask;
64 unsigned long flags; 64 unsigned long flags;
65 65
66 irq -= I8259A_IRQ_BASE; 66 irq -= I8259A_IRQ_BASE;
67 mask = 1 << irq; 67 mask = 1 << irq;
68 spin_lock_irqsave(&i8259A_lock, flags); 68 raw_spin_lock_irqsave(&i8259A_lock, flags);
69 cached_irq_mask |= mask; 69 cached_irq_mask |= mask;
70 if (irq & 8) 70 if (irq & 8)
71 outb(cached_slave_mask, PIC_SLAVE_IMR); 71 outb(cached_slave_mask, PIC_SLAVE_IMR);
72 else 72 else
73 outb(cached_master_mask, PIC_MASTER_IMR); 73 outb(cached_master_mask, PIC_MASTER_IMR);
74 spin_unlock_irqrestore(&i8259A_lock, flags); 74 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
75 } 75 }
76 76
77 static void enable_8259A_irq(unsigned int irq) 77 static void enable_8259A_irq(unsigned int irq)
78 { 78 {
79 unsigned int mask; 79 unsigned int mask;
80 unsigned long flags; 80 unsigned long flags;
81 81
82 irq -= I8259A_IRQ_BASE; 82 irq -= I8259A_IRQ_BASE;
83 mask = ~(1 << irq); 83 mask = ~(1 << irq);
84 spin_lock_irqsave(&i8259A_lock, flags); 84 raw_spin_lock_irqsave(&i8259A_lock, flags);
85 cached_irq_mask &= mask; 85 cached_irq_mask &= mask;
86 if (irq & 8) 86 if (irq & 8)
87 outb(cached_slave_mask, PIC_SLAVE_IMR); 87 outb(cached_slave_mask, PIC_SLAVE_IMR);
88 else 88 else
89 outb(cached_master_mask, PIC_MASTER_IMR); 89 outb(cached_master_mask, PIC_MASTER_IMR);
90 spin_unlock_irqrestore(&i8259A_lock, flags); 90 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
91 } 91 }
92 92
93 int i8259A_irq_pending(unsigned int irq) 93 int i8259A_irq_pending(unsigned int irq)
94 { 94 {
95 unsigned int mask; 95 unsigned int mask;
96 unsigned long flags; 96 unsigned long flags;
97 int ret; 97 int ret;
98 98
99 irq -= I8259A_IRQ_BASE; 99 irq -= I8259A_IRQ_BASE;
100 mask = 1 << irq; 100 mask = 1 << irq;
101 spin_lock_irqsave(&i8259A_lock, flags); 101 raw_spin_lock_irqsave(&i8259A_lock, flags);
102 if (irq < 8) 102 if (irq < 8)
103 ret = inb(PIC_MASTER_CMD) & mask; 103 ret = inb(PIC_MASTER_CMD) & mask;
104 else 104 else
105 ret = inb(PIC_SLAVE_CMD) & (mask >> 8); 105 ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
106 spin_unlock_irqrestore(&i8259A_lock, flags); 106 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
107 107
108 return ret; 108 return ret;
109 } 109 }
110 110
111 void make_8259A_irq(unsigned int irq) 111 void make_8259A_irq(unsigned int irq)
112 { 112 {
113 disable_irq_nosync(irq); 113 disable_irq_nosync(irq);
114 set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); 114 set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
115 enable_irq(irq); 115 enable_irq(irq);
116 } 116 }
117 117
118 /* 118 /*
119 * This function assumes to be called rarely. Switching between 119 * This function assumes to be called rarely. Switching between
120 * 8259A registers is slow. 120 * 8259A registers is slow.
121 * This has to be protected by the irq controller spinlock 121 * This has to be protected by the irq controller spinlock
122 * before being called. 122 * before being called.
123 */ 123 */
124 static inline int i8259A_irq_real(unsigned int irq) 124 static inline int i8259A_irq_real(unsigned int irq)
125 { 125 {
126 int value; 126 int value;
127 int irqmask = 1 << irq; 127 int irqmask = 1 << irq;
128 128
129 if (irq < 8) { 129 if (irq < 8) {
130 outb(0x0B, PIC_MASTER_CMD); /* ISR register */ 130 outb(0x0B, PIC_MASTER_CMD); /* ISR register */
131 value = inb(PIC_MASTER_CMD) & irqmask; 131 value = inb(PIC_MASTER_CMD) & irqmask;
132 outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ 132 outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */
133 return value; 133 return value;
134 } 134 }
135 outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ 135 outb(0x0B, PIC_SLAVE_CMD); /* ISR register */
136 value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); 136 value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
137 outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ 137 outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */
138 return value; 138 return value;
139 } 139 }
140 140
141 /* 141 /*
142 * Careful! The 8259A is a fragile beast, it pretty 142 * Careful! The 8259A is a fragile beast, it pretty
143 * much _has_ to be done exactly like this (mask it 143 * much _has_ to be done exactly like this (mask it
144 * first, _then_ send the EOI, and the order of EOI 144 * first, _then_ send the EOI, and the order of EOI
145 * to the two 8259s is important! 145 * to the two 8259s is important!
146 */ 146 */
147 static void mask_and_ack_8259A(unsigned int irq) 147 static void mask_and_ack_8259A(unsigned int irq)
148 { 148 {
149 unsigned int irqmask; 149 unsigned int irqmask;
150 unsigned long flags; 150 unsigned long flags;
151 151
152 irq -= I8259A_IRQ_BASE; 152 irq -= I8259A_IRQ_BASE;
153 irqmask = 1 << irq; 153 irqmask = 1 << irq;
154 spin_lock_irqsave(&i8259A_lock, flags); 154 raw_spin_lock_irqsave(&i8259A_lock, flags);
155 /* 155 /*
156 * Lightweight spurious IRQ detection. We do not want 156 * Lightweight spurious IRQ detection. We do not want
157 * to overdo spurious IRQ handling - it's usually a sign 157 * to overdo spurious IRQ handling - it's usually a sign
158 * of hardware problems, so we only do the checks we can 158 * of hardware problems, so we only do the checks we can
159 * do without slowing down good hardware unnecessarily. 159 * do without slowing down good hardware unnecessarily.
160 * 160 *
161 * Note that IRQ7 and IRQ15 (the two spurious IRQs 161 * Note that IRQ7 and IRQ15 (the two spurious IRQs
162 * usually resulting from the 8259A-1|2 PICs) occur 162 * usually resulting from the 8259A-1|2 PICs) occur
163 * even if the IRQ is masked in the 8259A. Thus we 163 * even if the IRQ is masked in the 8259A. Thus we
164 * can check spurious 8259A IRQs without doing the 164 * can check spurious 8259A IRQs without doing the
165 * quite slow i8259A_irq_real() call for every IRQ. 165 * quite slow i8259A_irq_real() call for every IRQ.
166 * This does not cover 100% of spurious interrupts, 166 * This does not cover 100% of spurious interrupts,
167 * but should be enough to warn the user that there 167 * but should be enough to warn the user that there
168 * is something bad going on ... 168 * is something bad going on ...
169 */ 169 */
170 if (cached_irq_mask & irqmask) 170 if (cached_irq_mask & irqmask)
171 goto spurious_8259A_irq; 171 goto spurious_8259A_irq;
172 cached_irq_mask |= irqmask; 172 cached_irq_mask |= irqmask;
173 173
174 handle_real_irq: 174 handle_real_irq:
175 if (irq & 8) { 175 if (irq & 8) {
176 inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ 176 inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */
177 outb(cached_slave_mask, PIC_SLAVE_IMR); 177 outb(cached_slave_mask, PIC_SLAVE_IMR);
178 outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ 178 outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */
179 outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ 179 outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */
180 } else { 180 } else {
181 inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ 181 inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */
182 outb(cached_master_mask, PIC_MASTER_IMR); 182 outb(cached_master_mask, PIC_MASTER_IMR);
183 outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ 183 outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */
184 } 184 }
185 smtc_im_ack_irq(irq); 185 smtc_im_ack_irq(irq);
186 spin_unlock_irqrestore(&i8259A_lock, flags); 186 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
187 return; 187 return;
188 188
189 spurious_8259A_irq: 189 spurious_8259A_irq:
190 /* 190 /*
191 * this is the slow path - should happen rarely. 191 * this is the slow path - should happen rarely.
192 */ 192 */
193 if (i8259A_irq_real(irq)) 193 if (i8259A_irq_real(irq))
194 /* 194 /*
195 * oops, the IRQ _is_ in service according to the 195 * oops, the IRQ _is_ in service according to the
196 * 8259A - not spurious, go handle it. 196 * 8259A - not spurious, go handle it.
197 */ 197 */
198 goto handle_real_irq; 198 goto handle_real_irq;
199 199
200 { 200 {
201 static int spurious_irq_mask; 201 static int spurious_irq_mask;
202 /* 202 /*
203 * At this point we can be sure the IRQ is spurious, 203 * At this point we can be sure the IRQ is spurious,
204 * lets ACK and report it. [once per IRQ] 204 * lets ACK and report it. [once per IRQ]
205 */ 205 */
206 if (!(spurious_irq_mask & irqmask)) { 206 if (!(spurious_irq_mask & irqmask)) {
207 printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); 207 printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
208 spurious_irq_mask |= irqmask; 208 spurious_irq_mask |= irqmask;
209 } 209 }
210 atomic_inc(&irq_err_count); 210 atomic_inc(&irq_err_count);
211 /* 211 /*
212 * Theoretically we do not have to handle this IRQ, 212 * Theoretically we do not have to handle this IRQ,
213 * but in Linux this does not cause problems and is 213 * but in Linux this does not cause problems and is
214 * simpler for us. 214 * simpler for us.
215 */ 215 */
216 goto handle_real_irq; 216 goto handle_real_irq;
217 } 217 }
218 } 218 }
219 219
220 static int i8259A_resume(struct sys_device *dev) 220 static int i8259A_resume(struct sys_device *dev)
221 { 221 {
222 if (i8259A_auto_eoi >= 0) 222 if (i8259A_auto_eoi >= 0)
223 init_8259A(i8259A_auto_eoi); 223 init_8259A(i8259A_auto_eoi);
224 return 0; 224 return 0;
225 } 225 }
226 226
227 static int i8259A_shutdown(struct sys_device *dev) 227 static int i8259A_shutdown(struct sys_device *dev)
228 { 228 {
229 /* Put the i8259A into a quiescent state that 229 /* Put the i8259A into a quiescent state that
230 * the kernel initialization code can get it 230 * the kernel initialization code can get it
231 * out of. 231 * out of.
232 */ 232 */
233 if (i8259A_auto_eoi >= 0) { 233 if (i8259A_auto_eoi >= 0) {
234 outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ 234 outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
235 outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ 235 outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */
236 } 236 }
237 return 0; 237 return 0;
238 } 238 }
239 239
240 static struct sysdev_class i8259_sysdev_class = { 240 static struct sysdev_class i8259_sysdev_class = {
241 .name = "i8259", 241 .name = "i8259",
242 .resume = i8259A_resume, 242 .resume = i8259A_resume,
243 .shutdown = i8259A_shutdown, 243 .shutdown = i8259A_shutdown,
244 }; 244 };
245 245
246 static struct sys_device device_i8259A = { 246 static struct sys_device device_i8259A = {
247 .id = 0, 247 .id = 0,
248 .cls = &i8259_sysdev_class, 248 .cls = &i8259_sysdev_class,
249 }; 249 };
250 250
251 static int __init i8259A_init_sysfs(void) 251 static int __init i8259A_init_sysfs(void)
252 { 252 {
253 int error = sysdev_class_register(&i8259_sysdev_class); 253 int error = sysdev_class_register(&i8259_sysdev_class);
254 if (!error) 254 if (!error)
255 error = sysdev_register(&device_i8259A); 255 error = sysdev_register(&device_i8259A);
256 return error; 256 return error;
257 } 257 }
258 258
259 device_initcall(i8259A_init_sysfs); 259 device_initcall(i8259A_init_sysfs);
260 260
261 static void init_8259A(int auto_eoi) 261 static void init_8259A(int auto_eoi)
262 { 262 {
263 unsigned long flags; 263 unsigned long flags;
264 264
265 i8259A_auto_eoi = auto_eoi; 265 i8259A_auto_eoi = auto_eoi;
266 266
267 spin_lock_irqsave(&i8259A_lock, flags); 267 raw_spin_lock_irqsave(&i8259A_lock, flags);
268 268
269 outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ 269 outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
270 outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ 270 outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
271 271
272 /* 272 /*
273 * outb_p - this has to work on a wide range of PC hardware. 273 * outb_p - this has to work on a wide range of PC hardware.
274 */ 274 */
275 outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ 275 outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
276 outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ 276 outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */
277 outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ 277 outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */
278 if (auto_eoi) /* master does Auto EOI */ 278 if (auto_eoi) /* master does Auto EOI */
279 outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); 279 outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
280 else /* master expects normal EOI */ 280 else /* master expects normal EOI */
281 outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); 281 outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
282 282
283 outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ 283 outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */
284 outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ 284 outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */
285 outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ 285 outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */
286 outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ 286 outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
287 if (auto_eoi) 287 if (auto_eoi)
288 /* 288 /*
289 * In AEOI mode we just have to mask the interrupt 289 * In AEOI mode we just have to mask the interrupt
290 * when acking. 290 * when acking.
291 */ 291 */
292 i8259A_chip.mask_ack = disable_8259A_irq; 292 i8259A_chip.mask_ack = disable_8259A_irq;
293 else 293 else
294 i8259A_chip.mask_ack = mask_and_ack_8259A; 294 i8259A_chip.mask_ack = mask_and_ack_8259A;
295 295
296 udelay(100); /* wait for 8259A to initialize */ 296 udelay(100); /* wait for 8259A to initialize */
297 297
298 outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ 298 outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
299 outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ 299 outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */
300 300
301 spin_unlock_irqrestore(&i8259A_lock, flags); 301 raw_spin_unlock_irqrestore(&i8259A_lock, flags);
302 } 302 }
303 303
304 /* 304 /*
305 * IRQ2 is cascade interrupt to second interrupt controller 305 * IRQ2 is cascade interrupt to second interrupt controller
306 */ 306 */
307 static struct irqaction irq2 = { 307 static struct irqaction irq2 = {
308 .handler = no_action, 308 .handler = no_action,
309 .name = "cascade", 309 .name = "cascade",
310 }; 310 };
311 311
312 static struct resource pic1_io_resource = { 312 static struct resource pic1_io_resource = {
313 .name = "pic1", 313 .name = "pic1",
314 .start = PIC_MASTER_CMD, 314 .start = PIC_MASTER_CMD,
315 .end = PIC_MASTER_IMR, 315 .end = PIC_MASTER_IMR,
316 .flags = IORESOURCE_BUSY 316 .flags = IORESOURCE_BUSY
317 }; 317 };
318 318
319 static struct resource pic2_io_resource = { 319 static struct resource pic2_io_resource = {
320 .name = "pic2", 320 .name = "pic2",
321 .start = PIC_SLAVE_CMD, 321 .start = PIC_SLAVE_CMD,
322 .end = PIC_SLAVE_IMR, 322 .end = PIC_SLAVE_IMR,
323 .flags = IORESOURCE_BUSY 323 .flags = IORESOURCE_BUSY
324 }; 324 };
325 325
326 /* 326 /*
327 * On systems with i8259-style interrupt controllers we assume for 327 * On systems with i8259-style interrupt controllers we assume for
328 * driver compatibility reasons interrupts 0 - 15 to be the i8259 328 * driver compatibility reasons interrupts 0 - 15 to be the i8259
329 * interrupts even if the hardware uses a different interrupt numbering. 329 * interrupts even if the hardware uses a different interrupt numbering.
330 */ 330 */
331 void __init init_i8259_irqs(void) 331 void __init init_i8259_irqs(void)
332 { 332 {
333 int i; 333 int i;
334 334
335 insert_resource(&ioport_resource, &pic1_io_resource); 335 insert_resource(&ioport_resource, &pic1_io_resource);
336 insert_resource(&ioport_resource, &pic2_io_resource); 336 insert_resource(&ioport_resource, &pic2_io_resource);
337 337
338 init_8259A(0); 338 init_8259A(0);
339 339
340 for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) { 340 for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) {
341 set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); 341 set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq);
342 set_irq_probe(i); 342 set_irq_probe(i);
343 } 343 }
344 344
345 setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); 345 setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
346 } 346 }
347 347
arch/mips/loongson/lemote-2f/irq.c
1 /* 1 /*
2 * Copyright (C) 2007 Lemote Inc. 2 * Copyright (C) 2007 Lemote Inc.
3 * Author: Fuxin Zhang, zhangfx@lemote.com 3 * Author: Fuxin Zhang, zhangfx@lemote.com
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify it 5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the 6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your 7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. 8 * option) any later version.
9 */ 9 */
10 10
11 #include <linux/interrupt.h> 11 #include <linux/interrupt.h>
12 #include <linux/module.h> 12 #include <linux/module.h>
13 13
14 #include <asm/irq_cpu.h> 14 #include <asm/irq_cpu.h>
15 #include <asm/i8259.h> 15 #include <asm/i8259.h>
16 #include <asm/mipsregs.h> 16 #include <asm/mipsregs.h>
17 17
18 #include <loongson.h> 18 #include <loongson.h>
19 #include <machine.h> 19 #include <machine.h>
20 20
21 #define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */ 21 #define LOONGSON_TIMER_IRQ (MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
22 #define LOONGSON_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */ 22 #define LOONGSON_PERFCNT_IRQ (MIPS_CPU_IRQ_BASE + 6) /* cpu perf counter */
23 #define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */ 23 #define LOONGSON_NORTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 6) /* bonito */
24 #define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */ 24 #define LOONGSON_UART_IRQ (MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
25 #define LOONGSON_SOUTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 2) /* i8259 */ 25 #define LOONGSON_SOUTH_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 2) /* i8259 */
26 26
27 #define LOONGSON_INT_BIT_INT0 (1 << 11) 27 #define LOONGSON_INT_BIT_INT0 (1 << 11)
28 #define LOONGSON_INT_BIT_INT1 (1 << 12) 28 #define LOONGSON_INT_BIT_INT1 (1 << 12)
29 29
30 /* 30 /*
31 * The generic i8259_irq() make the kernel hang on booting. Since we cannot 31 * The generic i8259_irq() make the kernel hang on booting. Since we cannot
32 * get the irq via the IRR directly, we access the ISR instead. 32 * get the irq via the IRR directly, we access the ISR instead.
33 */ 33 */
34 int mach_i8259_irq(void) 34 int mach_i8259_irq(void)
35 { 35 {
36 int irq, isr; 36 int irq, isr;
37 37
38 irq = -1; 38 irq = -1;
39 39
40 if ((LOONGSON_INTISR & LOONGSON_INTEN) & LOONGSON_INT_BIT_INT0) { 40 if ((LOONGSON_INTISR & LOONGSON_INTEN) & LOONGSON_INT_BIT_INT0) {
41 spin_lock(&i8259A_lock); 41 raw_spin_lock(&i8259A_lock);
42 isr = inb(PIC_MASTER_CMD) & 42 isr = inb(PIC_MASTER_CMD) &
43 ~inb(PIC_MASTER_IMR) & ~(1 << PIC_CASCADE_IR); 43 ~inb(PIC_MASTER_IMR) & ~(1 << PIC_CASCADE_IR);
44 if (!isr) 44 if (!isr)
45 isr = (inb(PIC_SLAVE_CMD) & ~inb(PIC_SLAVE_IMR)) << 8; 45 isr = (inb(PIC_SLAVE_CMD) & ~inb(PIC_SLAVE_IMR)) << 8;
46 irq = ffs(isr) - 1; 46 irq = ffs(isr) - 1;
47 if (unlikely(irq == 7)) { 47 if (unlikely(irq == 7)) {
48 /* 48 /*
49 * This may be a spurious interrupt. 49 * This may be a spurious interrupt.
50 * 50 *
51 * Read the interrupt status register (ISR). If the most 51 * Read the interrupt status register (ISR). If the most
52 * significant bit is not set then there is no valid 52 * significant bit is not set then there is no valid
53 * interrupt. 53 * interrupt.
54 */ 54 */
55 outb(0x0B, PIC_MASTER_ISR); /* ISR register */ 55 outb(0x0B, PIC_MASTER_ISR); /* ISR register */
56 if (~inb(PIC_MASTER_ISR) & 0x80) 56 if (~inb(PIC_MASTER_ISR) & 0x80)
57 irq = -1; 57 irq = -1;
58 } 58 }
59 spin_unlock(&i8259A_lock); 59 raw_spin_unlock(&i8259A_lock);
60 } 60 }
61 61
62 return irq; 62 return irq;
63 } 63 }
64 EXPORT_SYMBOL(mach_i8259_irq); 64 EXPORT_SYMBOL(mach_i8259_irq);
65 65
66 static void i8259_irqdispatch(void) 66 static void i8259_irqdispatch(void)
67 { 67 {
68 int irq; 68 int irq;
69 69
70 irq = mach_i8259_irq(); 70 irq = mach_i8259_irq();
71 if (irq >= 0) 71 if (irq >= 0)
72 do_IRQ(irq); 72 do_IRQ(irq);
73 else 73 else
74 spurious_interrupt(); 74 spurious_interrupt();
75 } 75 }
76 76
77 void mach_irq_dispatch(unsigned int pending) 77 void mach_irq_dispatch(unsigned int pending)
78 { 78 {
79 if (pending & CAUSEF_IP7) 79 if (pending & CAUSEF_IP7)
80 do_IRQ(LOONGSON_TIMER_IRQ); 80 do_IRQ(LOONGSON_TIMER_IRQ);
81 else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */ 81 else if (pending & CAUSEF_IP6) { /* North Bridge, Perf counter */
82 #ifdef CONFIG_OPROFILE 82 #ifdef CONFIG_OPROFILE
83 do_IRQ(LOONGSON2_PERFCNT_IRQ); 83 do_IRQ(LOONGSON2_PERFCNT_IRQ);
84 #endif 84 #endif
85 bonito_irqdispatch(); 85 bonito_irqdispatch();
86 } else if (pending & CAUSEF_IP3) /* CPU UART */ 86 } else if (pending & CAUSEF_IP3) /* CPU UART */
87 do_IRQ(LOONGSON_UART_IRQ); 87 do_IRQ(LOONGSON_UART_IRQ);
88 else if (pending & CAUSEF_IP2) /* South Bridge */ 88 else if (pending & CAUSEF_IP2) /* South Bridge */
89 i8259_irqdispatch(); 89 i8259_irqdispatch();
90 else 90 else
91 spurious_interrupt(); 91 spurious_interrupt();
92 } 92 }
93 93
94 void __init set_irq_trigger_mode(void) 94 void __init set_irq_trigger_mode(void)
95 { 95 {
96 /* setup cs5536 as high level trigger */ 96 /* setup cs5536 as high level trigger */
97 LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1; 97 LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
98 LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1); 98 LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
99 } 99 }
100 100
101 static irqreturn_t ip6_action(int cpl, void *dev_id) 101 static irqreturn_t ip6_action(int cpl, void *dev_id)
102 { 102 {
103 return IRQ_HANDLED; 103 return IRQ_HANDLED;
104 } 104 }
105 105
106 struct irqaction ip6_irqaction = { 106 struct irqaction ip6_irqaction = {
107 .handler = ip6_action, 107 .handler = ip6_action,
108 .name = "cascade", 108 .name = "cascade",
109 .flags = IRQF_SHARED, 109 .flags = IRQF_SHARED,
110 }; 110 };
111 111
112 struct irqaction cascade_irqaction = { 112 struct irqaction cascade_irqaction = {
113 .handler = no_action, 113 .handler = no_action,
114 .name = "cascade", 114 .name = "cascade",
115 }; 115 };
116 116
117 void __init mach_init_irq(void) 117 void __init mach_init_irq(void)
118 { 118 {
119 /* init all controller 119 /* init all controller
120 * 0-15 ------> i8259 interrupt 120 * 0-15 ------> i8259 interrupt
121 * 16-23 ------> mips cpu interrupt 121 * 16-23 ------> mips cpu interrupt
122 * 32-63 ------> bonito irq 122 * 32-63 ------> bonito irq
123 */ 123 */
124 124
125 /* Sets the first-level interrupt dispatcher. */ 125 /* Sets the first-level interrupt dispatcher. */
126 mips_cpu_irq_init(); 126 mips_cpu_irq_init();
127 init_i8259_irqs(); 127 init_i8259_irqs();
128 bonito_irq_init(); 128 bonito_irq_init();
129 129
130 /* setup north bridge irq (bonito) */ 130 /* setup north bridge irq (bonito) */
131 setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction); 131 setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
132 /* setup source bridge irq (i8259) */ 132 /* setup source bridge irq (i8259) */
133 setup_irq(LOONGSON_SOUTH_BRIDGE_IRQ, &cascade_irqaction); 133 setup_irq(LOONGSON_SOUTH_BRIDGE_IRQ, &cascade_irqaction);
134 } 134 }
135 135