aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/kernel/i8259.c162
-rw-r--r--include/asm-mips/i8259.h37
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
22void enable_8259A_irq(unsigned int irq);
23void 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
31static int i8259A_auto_eoi;
34DEFINE_SPINLOCK(i8259A_lock); 32DEFINE_SPINLOCK(i8259A_lock);
35 33/* some platforms call this... */
36static 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
43void mask_and_ack_8259A(unsigned int); 34void mask_and_ack_8259A(unsigned int);
44 35
45static struct irq_chip i8259A_irq_type = { 36static 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 */
60static unsigned int cached_irq_mask = 0xffff; 50static 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
65void disable_8259A_irq(unsigned int irq) 55void 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)
109void make_8259A_irq(unsigned int irq) 99void 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
168handle_real_irq: 160handle_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
217static int i8259A_resume(struct sys_device *dev) 209static int i8259A_resume(struct sys_device *dev)
218{ 210{
219 init_8259A(0); 211 init_8259A(i8259A_auto_eoi);
212 return 0;
213}
214
215static 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
223static struct sysdev_class i8259_sysdev_class = { 226static 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
228static struct sys_device device_i8259A = { 232static 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
293static struct resource pic1_io_resource = { 297static 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
297static struct resource pic2_io_resource = { 304static 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
22extern spinlock_t i8259A_lock; 37extern spinlock_t i8259A_lock;
23 38
39extern void init_8259A(int auto_eoi);
40extern void enable_8259A_irq(unsigned int irq);
41extern void disable_8259A_irq(unsigned int irq);
42
24extern void init_i8259_irqs(void); 43extern 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 */