diff options
-rw-r--r-- | arch/mips/kernel/i8259.c | 162 | ||||
-rw-r--r-- | include/asm-mips/i8259.h | 37 |
2 files changed, 115 insertions, 84 deletions
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 2526c0ca4d81..b59a676c6d0e 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c | |||
@@ -19,9 +19,6 @@ | |||
19 | #include <asm/i8259.h> | 19 | #include <asm/i8259.h> |
20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
21 | 21 | ||
22 | void enable_8259A_irq(unsigned int irq); | ||
23 | void disable_8259A_irq(unsigned int irq); | ||
24 | |||
25 | /* | 22 | /* |
26 | * This is the 'legacy' 8259A Programmable Interrupt Controller, | 23 | * This is the 'legacy' 8259A Programmable Interrupt Controller, |
27 | * present in the majority of PC/AT boxes. | 24 | * present in the majority of PC/AT boxes. |
@@ -31,23 +28,16 @@ void disable_8259A_irq(unsigned int irq); | |||
31 | * moves to arch independent land | 28 | * moves to arch independent land |
32 | */ | 29 | */ |
33 | 30 | ||
31 | static int i8259A_auto_eoi; | ||
34 | DEFINE_SPINLOCK(i8259A_lock); | 32 | DEFINE_SPINLOCK(i8259A_lock); |
35 | 33 | /* some platforms call this... */ | |
36 | static void end_8259A_irq (unsigned int irq) | ||
37 | { | ||
38 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && | ||
39 | irq_desc[irq].action) | ||
40 | enable_8259A_irq(irq); | ||
41 | } | ||
42 | |||
43 | void mask_and_ack_8259A(unsigned int); | 34 | void mask_and_ack_8259A(unsigned int); |
44 | 35 | ||
45 | static struct irq_chip i8259A_irq_type = { | 36 | static struct irq_chip i8259A_chip = { |
46 | .typename = "XT-PIC", | 37 | .name = "XT-PIC", |
47 | .enable = enable_8259A_irq, | 38 | .mask = disable_8259A_irq, |
48 | .disable = disable_8259A_irq, | 39 | .unmask = enable_8259A_irq, |
49 | .ack = mask_and_ack_8259A, | 40 | .mask_ack = mask_and_ack_8259A, |
50 | .end = end_8259A_irq, | ||
51 | }; | 41 | }; |
52 | 42 | ||
53 | /* | 43 | /* |
@@ -59,8 +49,8 @@ static struct irq_chip i8259A_irq_type = { | |||
59 | */ | 49 | */ |
60 | static unsigned int cached_irq_mask = 0xffff; | 50 | static unsigned int cached_irq_mask = 0xffff; |
61 | 51 | ||
62 | #define cached_21 (cached_irq_mask) | 52 | #define cached_master_mask (cached_irq_mask) |
63 | #define cached_A1 (cached_irq_mask >> 8) | 53 | #define cached_slave_mask (cached_irq_mask >> 8) |
64 | 54 | ||
65 | void disable_8259A_irq(unsigned int irq) | 55 | void disable_8259A_irq(unsigned int irq) |
66 | { | 56 | { |
@@ -70,9 +60,9 @@ void disable_8259A_irq(unsigned int irq) | |||
70 | spin_lock_irqsave(&i8259A_lock, flags); | 60 | spin_lock_irqsave(&i8259A_lock, flags); |
71 | cached_irq_mask |= mask; | 61 | cached_irq_mask |= mask; |
72 | if (irq & 8) | 62 | if (irq & 8) |
73 | outb(cached_A1,0xA1); | 63 | outb(cached_slave_mask, PIC_SLAVE_IMR); |
74 | else | 64 | else |
75 | outb(cached_21,0x21); | 65 | outb(cached_master_mask, PIC_MASTER_IMR); |
76 | spin_unlock_irqrestore(&i8259A_lock, flags); | 66 | spin_unlock_irqrestore(&i8259A_lock, flags); |
77 | } | 67 | } |
78 | 68 | ||
@@ -84,9 +74,9 @@ void enable_8259A_irq(unsigned int irq) | |||
84 | spin_lock_irqsave(&i8259A_lock, flags); | 74 | spin_lock_irqsave(&i8259A_lock, flags); |
85 | cached_irq_mask &= mask; | 75 | cached_irq_mask &= mask; |
86 | if (irq & 8) | 76 | if (irq & 8) |
87 | outb(cached_A1,0xA1); | 77 | outb(cached_slave_mask, PIC_SLAVE_IMR); |
88 | else | 78 | else |
89 | outb(cached_21,0x21); | 79 | outb(cached_master_mask, PIC_MASTER_IMR); |
90 | spin_unlock_irqrestore(&i8259A_lock, flags); | 80 | spin_unlock_irqrestore(&i8259A_lock, flags); |
91 | } | 81 | } |
92 | 82 | ||
@@ -98,9 +88,9 @@ int i8259A_irq_pending(unsigned int irq) | |||
98 | 88 | ||
99 | spin_lock_irqsave(&i8259A_lock, flags); | 89 | spin_lock_irqsave(&i8259A_lock, flags); |
100 | if (irq < 8) | 90 | if (irq < 8) |
101 | ret = inb(0x20) & mask; | 91 | ret = inb(PIC_MASTER_CMD) & mask; |
102 | else | 92 | else |
103 | ret = inb(0xA0) & (mask >> 8); | 93 | ret = inb(PIC_SLAVE_CMD) & (mask >> 8); |
104 | spin_unlock_irqrestore(&i8259A_lock, flags); | 94 | spin_unlock_irqrestore(&i8259A_lock, flags); |
105 | 95 | ||
106 | return ret; | 96 | return ret; |
@@ -109,7 +99,7 @@ int i8259A_irq_pending(unsigned int irq) | |||
109 | void make_8259A_irq(unsigned int irq) | 99 | void make_8259A_irq(unsigned int irq) |
110 | { | 100 | { |
111 | disable_irq_nosync(irq); | 101 | disable_irq_nosync(irq); |
112 | set_irq_chip(irq, &i8259A_irq_type); | 102 | set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); |
113 | enable_irq(irq); | 103 | enable_irq(irq); |
114 | } | 104 | } |
115 | 105 | ||
@@ -125,14 +115,14 @@ static inline int i8259A_irq_real(unsigned int irq) | |||
125 | int irqmask = 1 << irq; | 115 | int irqmask = 1 << irq; |
126 | 116 | ||
127 | if (irq < 8) { | 117 | if (irq < 8) { |
128 | outb(0x0B,0x20); /* ISR register */ | 118 | outb(0x0B,PIC_MASTER_CMD); /* ISR register */ |
129 | value = inb(0x20) & irqmask; | 119 | value = inb(PIC_MASTER_CMD) & irqmask; |
130 | outb(0x0A,0x20); /* back to the IRR register */ | 120 | outb(0x0A,PIC_MASTER_CMD); /* back to the IRR register */ |
131 | return value; | 121 | return value; |
132 | } | 122 | } |
133 | outb(0x0B,0xA0); /* ISR register */ | 123 | outb(0x0B,PIC_SLAVE_CMD); /* ISR register */ |
134 | value = inb(0xA0) & (irqmask >> 8); | 124 | value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); |
135 | outb(0x0A,0xA0); /* back to the IRR register */ | 125 | outb(0x0A,PIC_SLAVE_CMD); /* back to the IRR register */ |
136 | return value; | 126 | return value; |
137 | } | 127 | } |
138 | 128 | ||
@@ -149,17 +139,19 @@ void mask_and_ack_8259A(unsigned int irq) | |||
149 | 139 | ||
150 | spin_lock_irqsave(&i8259A_lock, flags); | 140 | spin_lock_irqsave(&i8259A_lock, flags); |
151 | /* | 141 | /* |
152 | * Lightweight spurious IRQ detection. We do not want to overdo | 142 | * Lightweight spurious IRQ detection. We do not want |
153 | * spurious IRQ handling - it's usually a sign of hardware problems, so | 143 | * to overdo spurious IRQ handling - it's usually a sign |
154 | * we only do the checks we can do without slowing down good hardware | 144 | * of hardware problems, so we only do the checks we can |
155 | * nnecesserily. | 145 | * do without slowing down good hardware unnecessarily. |
156 | * | 146 | * |
157 | * Note that IRQ7 and IRQ15 (the two spurious IRQs usually resulting | 147 | * Note that IRQ7 and IRQ15 (the two spurious IRQs |
158 | * rom the 8259A-1|2 PICs) occur even if the IRQ is masked in the 8259A. | 148 | * usually resulting from the 8259A-1|2 PICs) occur |
159 | * Thus we can check spurious 8259A IRQs without doing the quite slow | 149 | * even if the IRQ is masked in the 8259A. Thus we |
160 | * i8259A_irq_real() call for every IRQ. This does not cover 100% of | 150 | * can check spurious 8259A IRQs without doing the |
161 | * spurious interrupts, but should be enough to warn the user that | 151 | * quite slow i8259A_irq_real() call for every IRQ. |
162 | * there is something bad going on ... | 152 | * This does not cover 100% of spurious interrupts, |
153 | * but should be enough to warn the user that there | ||
154 | * is something bad going on ... | ||
163 | */ | 155 | */ |
164 | if (cached_irq_mask & irqmask) | 156 | if (cached_irq_mask & irqmask) |
165 | goto spurious_8259A_irq; | 157 | goto spurious_8259A_irq; |
@@ -167,14 +159,14 @@ void mask_and_ack_8259A(unsigned int irq) | |||
167 | 159 | ||
168 | handle_real_irq: | 160 | handle_real_irq: |
169 | if (irq & 8) { | 161 | if (irq & 8) { |
170 | inb(0xA1); /* DUMMY - (do we need this?) */ | 162 | inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ |
171 | outb(cached_A1,0xA1); | 163 | outb(cached_slave_mask, PIC_SLAVE_IMR); |
172 | outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ | 164 | outb(0x60+(irq&7),PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ |
173 | outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ | 165 | outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ |
174 | } else { | 166 | } else { |
175 | inb(0x21); /* DUMMY - (do we need this?) */ | 167 | inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ |
176 | outb(cached_21,0x21); | 168 | outb(cached_master_mask, PIC_MASTER_IMR); |
177 | outb(0x60+irq,0x20); /* 'Specific EOI' to master */ | 169 | outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */ |
178 | } | 170 | } |
179 | #ifdef CONFIG_MIPS_MT_SMTC | 171 | #ifdef CONFIG_MIPS_MT_SMTC |
180 | if (irq_hwmask[irq] & ST0_IM) | 172 | if (irq_hwmask[irq] & ST0_IM) |
@@ -195,7 +187,7 @@ spurious_8259A_irq: | |||
195 | goto handle_real_irq; | 187 | goto handle_real_irq; |
196 | 188 | ||
197 | { | 189 | { |
198 | static int spurious_irq_mask = 0; | 190 | static int spurious_irq_mask; |
199 | /* | 191 | /* |
200 | * At this point we can be sure the IRQ is spurious, | 192 | * At this point we can be sure the IRQ is spurious, |
201 | * lets ACK and report it. [once per IRQ] | 193 | * lets ACK and report it. [once per IRQ] |
@@ -216,13 +208,25 @@ spurious_8259A_irq: | |||
216 | 208 | ||
217 | static int i8259A_resume(struct sys_device *dev) | 209 | static int i8259A_resume(struct sys_device *dev) |
218 | { | 210 | { |
219 | init_8259A(0); | 211 | init_8259A(i8259A_auto_eoi); |
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int i8259A_shutdown(struct sys_device *dev) | ||
216 | { | ||
217 | /* Put the i8259A into a quiescent state that | ||
218 | * the kernel initialization code can get it | ||
219 | * out of. | ||
220 | */ | ||
221 | outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ | ||
222 | outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ | ||
220 | return 0; | 223 | return 0; |
221 | } | 224 | } |
222 | 225 | ||
223 | static struct sysdev_class i8259_sysdev_class = { | 226 | static struct sysdev_class i8259_sysdev_class = { |
224 | set_kset_name("i8259"), | 227 | set_kset_name("i8259"), |
225 | .resume = i8259A_resume, | 228 | .resume = i8259A_resume, |
229 | .shutdown = i8259A_shutdown, | ||
226 | }; | 230 | }; |
227 | 231 | ||
228 | static struct sys_device device_i8259A = { | 232 | static struct sys_device device_i8259A = { |
@@ -244,41 +248,41 @@ void __init init_8259A(int auto_eoi) | |||
244 | { | 248 | { |
245 | unsigned long flags; | 249 | unsigned long flags; |
246 | 250 | ||
251 | i8259A_auto_eoi = auto_eoi; | ||
252 | |||
247 | spin_lock_irqsave(&i8259A_lock, flags); | 253 | spin_lock_irqsave(&i8259A_lock, flags); |
248 | 254 | ||
249 | outb(0xff, 0x21); /* mask all of 8259A-1 */ | 255 | outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ |
250 | outb(0xff, 0xA1); /* mask all of 8259A-2 */ | 256 | outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ |
251 | 257 | ||
252 | /* | 258 | /* |
253 | * outb_p - this has to work on a wide range of PC hardware. | 259 | * outb_p - this has to work on a wide range of PC hardware. |
254 | */ | 260 | */ |
255 | outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ | 261 | outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ |
256 | outb_p(0x00, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x00-0x07 */ | 262 | outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ |
257 | outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ | 263 | outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ |
258 | if (auto_eoi) | 264 | if (auto_eoi) /* master does Auto EOI */ |
259 | outb_p(0x03, 0x21); /* master does Auto EOI */ | 265 | outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); |
260 | else | 266 | else /* master expects normal EOI */ |
261 | outb_p(0x01, 0x21); /* master expects normal EOI */ | 267 | outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); |
262 | 268 | ||
263 | outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ | 269 | outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ |
264 | outb_p(0x08, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x08-0x0f */ | 270 | outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ |
265 | outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ | 271 | outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ |
266 | outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode | 272 | outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ |
267 | is to be investigated) */ | ||
268 | |||
269 | if (auto_eoi) | 273 | if (auto_eoi) |
270 | /* | 274 | /* |
271 | * in AEOI mode we just have to mask the interrupt | 275 | * In AEOI mode we just have to mask the interrupt |
272 | * when acking. | 276 | * when acking. |
273 | */ | 277 | */ |
274 | i8259A_irq_type.ack = disable_8259A_irq; | 278 | i8259A_chip.mask_ack = disable_8259A_irq; |
275 | else | 279 | else |
276 | i8259A_irq_type.ack = mask_and_ack_8259A; | 280 | i8259A_chip.mask_ack = mask_and_ack_8259A; |
277 | 281 | ||
278 | udelay(100); /* wait for 8259A to initialize */ | 282 | udelay(100); /* wait for 8259A to initialize */ |
279 | 283 | ||
280 | outb(cached_21, 0x21); /* restore master IRQ mask */ | 284 | outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ |
281 | outb(cached_A1, 0xA1); /* restore slave IRQ mask */ | 285 | outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ |
282 | 286 | ||
283 | spin_unlock_irqrestore(&i8259A_lock, flags); | 287 | spin_unlock_irqrestore(&i8259A_lock, flags); |
284 | } | 288 | } |
@@ -291,11 +295,17 @@ static struct irqaction irq2 = { | |||
291 | }; | 295 | }; |
292 | 296 | ||
293 | static struct resource pic1_io_resource = { | 297 | static struct resource pic1_io_resource = { |
294 | .name = "pic1", .start = 0x20, .end = 0x21, .flags = IORESOURCE_BUSY | 298 | .name = "pic1", |
299 | .start = PIC_MASTER_CMD, | ||
300 | .end = PIC_MASTER_IMR, | ||
301 | .flags = IORESOURCE_BUSY | ||
295 | }; | 302 | }; |
296 | 303 | ||
297 | static struct resource pic2_io_resource = { | 304 | static struct resource pic2_io_resource = { |
298 | .name = "pic2", .start = 0xa0, .end = 0xa1, .flags = IORESOURCE_BUSY | 305 | .name = "pic2", |
306 | .start = PIC_SLAVE_CMD, | ||
307 | .end = PIC_SLAVE_IMR, | ||
308 | .flags = IORESOURCE_BUSY | ||
299 | }; | 309 | }; |
300 | 310 | ||
301 | /* | 311 | /* |
@@ -313,7 +323,7 @@ void __init init_i8259_irqs (void) | |||
313 | init_8259A(0); | 323 | init_8259A(0); |
314 | 324 | ||
315 | for (i = 0; i < 16; i++) | 325 | for (i = 0; i < 16; i++) |
316 | set_irq_chip(i, &i8259A_irq_type); | 326 | set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); |
317 | 327 | ||
318 | setup_irq(2, &irq2); | 328 | setup_irq(PIC_CASCADE_IR, &irq2); |
319 | } | 329 | } |
diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h index 0214abe3f0af..4df8d8b118c0 100644 --- a/include/asm-mips/i8259.h +++ b/include/asm-mips/i8259.h | |||
@@ -19,10 +19,31 @@ | |||
19 | 19 | ||
20 | #include <asm/io.h> | 20 | #include <asm/io.h> |
21 | 21 | ||
22 | /* i8259A PIC registers */ | ||
23 | #define PIC_MASTER_CMD 0x20 | ||
24 | #define PIC_MASTER_IMR 0x21 | ||
25 | #define PIC_MASTER_ISR PIC_MASTER_CMD | ||
26 | #define PIC_MASTER_POLL PIC_MASTER_ISR | ||
27 | #define PIC_MASTER_OCW3 PIC_MASTER_ISR | ||
28 | #define PIC_SLAVE_CMD 0xa0 | ||
29 | #define PIC_SLAVE_IMR 0xa1 | ||
30 | |||
31 | /* i8259A PIC related value */ | ||
32 | #define PIC_CASCADE_IR 2 | ||
33 | #define MASTER_ICW4_DEFAULT 0x01 | ||
34 | #define SLAVE_ICW4_DEFAULT 0x01 | ||
35 | #define PIC_ICW4_AEOI 2 | ||
36 | |||
22 | extern spinlock_t i8259A_lock; | 37 | extern spinlock_t i8259A_lock; |
23 | 38 | ||
39 | extern void init_8259A(int auto_eoi); | ||
40 | extern void enable_8259A_irq(unsigned int irq); | ||
41 | extern void disable_8259A_irq(unsigned int irq); | ||
42 | |||
24 | extern void init_i8259_irqs(void); | 43 | extern void init_i8259_irqs(void); |
25 | 44 | ||
45 | #define I8259A_IRQ_BASE 0 | ||
46 | |||
26 | /* | 47 | /* |
27 | * Do the traditional i8259 interrupt polling thing. This is for the few | 48 | * Do the traditional i8259 interrupt polling thing. This is for the few |
28 | * cases where no better interrupt acknowledge method is available and we | 49 | * cases where no better interrupt acknowledge method is available and we |
@@ -35,15 +56,15 @@ static inline int i8259_irq(void) | |||
35 | spin_lock(&i8259A_lock); | 56 | spin_lock(&i8259A_lock); |
36 | 57 | ||
37 | /* Perform an interrupt acknowledge cycle on controller 1. */ | 58 | /* Perform an interrupt acknowledge cycle on controller 1. */ |
38 | outb(0x0C, 0x20); /* prepare for poll */ | 59 | outb(0x0C, PIC_MASTER_CMD); /* prepare for poll */ |
39 | irq = inb(0x20) & 7; | 60 | irq = inb(PIC_MASTER_CMD) & 7; |
40 | if (irq == 2) { | 61 | if (irq == PIC_CASCADE_IR) { |
41 | /* | 62 | /* |
42 | * Interrupt is cascaded so perform interrupt | 63 | * Interrupt is cascaded so perform interrupt |
43 | * acknowledge on controller 2. | 64 | * acknowledge on controller 2. |
44 | */ | 65 | */ |
45 | outb(0x0C, 0xA0); /* prepare for poll */ | 66 | outb(0x0C, PIC_SLAVE_CMD); /* prepare for poll */ |
46 | irq = (inb(0xA0) & 7) + 8; | 67 | irq = (inb(PIC_SLAVE_CMD) & 7) + 8; |
47 | } | 68 | } |
48 | 69 | ||
49 | if (unlikely(irq == 7)) { | 70 | if (unlikely(irq == 7)) { |
@@ -54,14 +75,14 @@ static inline int i8259_irq(void) | |||
54 | * significant bit is not set then there is no valid | 75 | * significant bit is not set then there is no valid |
55 | * interrupt. | 76 | * interrupt. |
56 | */ | 77 | */ |
57 | outb(0x0B, 0x20); /* ISR register */ | 78 | outb(0x0B, PIC_MASTER_ISR); /* ISR register */ |
58 | if(~inb(0x20) & 0x80) | 79 | if(~inb(PIC_MASTER_ISR) & 0x80) |
59 | irq = -1; | 80 | irq = -1; |
60 | } | 81 | } |
61 | 82 | ||
62 | spin_unlock(&i8259A_lock); | 83 | spin_unlock(&i8259A_lock); |
63 | 84 | ||
64 | return irq; | 85 | return likely(irq >= 0) ? irq + I8259A_IRQ_BASE : irq; |
65 | } | 86 | } |
66 | 87 | ||
67 | #endif /* _ASM_I8259_H */ | 88 | #endif /* _ASM_I8259_H */ |