diff options
Diffstat (limited to 'arch/mips/kernel/i8259.c')
-rw-r--r-- | arch/mips/kernel/i8259.c | 162 |
1 files changed, 86 insertions, 76 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 | } |