1
2
3
4
5
6
7
8
9
10
11#include <linux/delay.h>
12#include <linux/init.h>
13#include <linux/ioport.h>
14#include <linux/interrupt.h>
15#include <linux/kernel.h>
16#include <linux/spinlock.h>
17#include <linux/sysdev.h>
18
19#include <asm/i8259.h>
20#include <asm/io.h>
21
22
23
24
25
26
27
28
29
30
31static int i8259A_auto_eoi = -1;
32DEFINE_SPINLOCK(i8259A_lock);
33static void disable_8259A_irq(unsigned int irq);
34static void enable_8259A_irq(unsigned int irq);
35static void mask_and_ack_8259A(unsigned int irq);
36static void init_8259A(int auto_eoi);
37
38static struct irq_chip i8259A_chip = {
39 .name = "XT-PIC",
40 .mask = disable_8259A_irq,
41 .disable = disable_8259A_irq,
42 .unmask = enable_8259A_irq,
43 .mask_ack = mask_and_ack_8259A,
44#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
45 .set_affinity = plat_set_irq_affinity,
46#endif
47};
48
49
50
51
52
53
54
55
56static unsigned int cached_irq_mask = 0xffff;
57
58#define cached_master_mask (cached_irq_mask)
59#define cached_slave_mask (cached_irq_mask >> 8)
60
61static void disable_8259A_irq(unsigned int irq)
62{
63 unsigned int mask;
64 unsigned long flags;
65
66 irq -= I8259A_IRQ_BASE;
67 mask = 1 << irq;
68 spin_lock_irqsave(&i8259A_lock, flags);
69 cached_irq_mask |= mask;
70 if (irq & 8)
71 outb(cached_slave_mask, PIC_SLAVE_IMR);
72 else
73 outb(cached_master_mask, PIC_MASTER_IMR);
74 spin_unlock_irqrestore(&i8259A_lock, flags);
75}
76
77static void enable_8259A_irq(unsigned int irq)
78{
79 unsigned int mask;
80 unsigned long flags;
81
82 irq -= I8259A_IRQ_BASE;
83 mask = ~(1 << irq);
84 spin_lock_irqsave(&i8259A_lock, flags);
85 cached_irq_mask &= mask;
86 if (irq & 8)
87 outb(cached_slave_mask, PIC_SLAVE_IMR);
88 else
89 outb(cached_master_mask, PIC_MASTER_IMR);
90 spin_unlock_irqrestore(&i8259A_lock, flags);
91}
92
93int i8259A_irq_pending(unsigned int irq)
94{
95 unsigned int mask;
96 unsigned long flags;
97 int ret;
98
99 irq -= I8259A_IRQ_BASE;
100 mask = 1 << irq;
101 spin_lock_irqsave(&i8259A_lock, flags);
102 if (irq < 8)
103 ret = inb(PIC_MASTER_CMD) & mask;
104 else
105 ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
106 spin_unlock_irqrestore(&i8259A_lock, flags);
107
108 return ret;
109}
110
111void make_8259A_irq(unsigned int irq)
112{
113 disable_irq_nosync(irq);
114 set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
115 enable_irq(irq);
116}
117
118
119
120
121
122
123
124static inline int i8259A_irq_real(unsigned int irq)
125{
126 int value;
127 int irqmask = 1 << irq;
128
129 if (irq < 8) {
130 outb(0x0B, PIC_MASTER_CMD);
131 value = inb(PIC_MASTER_CMD) & irqmask;
132 outb(0x0A, PIC_MASTER_CMD);
133 return value;
134 }
135 outb(0x0B, PIC_SLAVE_CMD);
136 value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
137 outb(0x0A, PIC_SLAVE_CMD);
138 return value;
139}
140
141
142
143
144
145
146
147static void mask_and_ack_8259A(unsigned int irq)
148{
149 unsigned int irqmask;
150 unsigned long flags;
151
152 irq -= I8259A_IRQ_BASE;
153 irqmask = 1 << irq;
154 spin_lock_irqsave(&i8259A_lock, flags);
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 if (cached_irq_mask & irqmask)
171 goto spurious_8259A_irq;
172 cached_irq_mask |= irqmask;
173
174handle_real_irq:
175 if (irq & 8) {
176 inb(PIC_SLAVE_IMR);
177 outb(cached_slave_mask, PIC_SLAVE_IMR);
178 outb(0x60+(irq&7), PIC_SLAVE_CMD);
179 outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD);
180 } else {
181 inb(PIC_MASTER_IMR);
182 outb(cached_master_mask, PIC_MASTER_IMR);
183 outb(0x60+irq, PIC_MASTER_CMD);
184 }
185 smtc_im_ack_irq(irq);
186 spin_unlock_irqrestore(&i8259A_lock, flags);
187 return;
188
189spurious_8259A_irq:
190
191
192
193 if (i8259A_irq_real(irq))
194
195
196
197
198 goto handle_real_irq;
199
200 {
201 static int spurious_irq_mask;
202
203
204
205
206 if (!(spurious_irq_mask & irqmask)) {
207 printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
208 spurious_irq_mask |= irqmask;
209 }
210 atomic_inc(&irq_err_count);
211
212
213
214
215
216 goto handle_real_irq;
217 }
218}
219
220static int i8259A_resume(struct sys_device *dev)
221{
222 if (i8259A_auto_eoi >= 0)
223 init_8259A(i8259A_auto_eoi);
224 return 0;
225}
226
227static int i8259A_shutdown(struct sys_device *dev)
228{
229
230
231
232
233 if (i8259A_auto_eoi >= 0) {
234 outb(0xff, PIC_MASTER_IMR);
235 outb(0xff, PIC_SLAVE_IMR);
236 }
237 return 0;
238}
239
240static struct sysdev_class i8259_sysdev_class = {
241 .name = "i8259",
242 .resume = i8259A_resume,
243 .shutdown = i8259A_shutdown,
244};
245
246static struct sys_device device_i8259A = {
247 .id = 0,
248 .cls = &i8259_sysdev_class,
249};
250
251static int __init i8259A_init_sysfs(void)
252{
253 int error = sysdev_class_register(&i8259_sysdev_class);
254 if (!error)
255 error = sysdev_register(&device_i8259A);
256 return error;
257}
258
259device_initcall(i8259A_init_sysfs);
260
261static void init_8259A(int auto_eoi)
262{
263 unsigned long flags;
264
265 i8259A_auto_eoi = auto_eoi;
266
267 spin_lock_irqsave(&i8259A_lock, flags);
268
269 outb(0xff, PIC_MASTER_IMR);
270 outb(0xff, PIC_SLAVE_IMR);
271
272
273
274
275 outb_p(0x11, PIC_MASTER_CMD);
276 outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR);
277 outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
278 if (auto_eoi)
279 outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
280 else
281 outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
282
283 outb_p(0x11, PIC_SLAVE_CMD);
284 outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR);
285 outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR);
286 outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
287 if (auto_eoi)
288
289
290
291
292 i8259A_chip.mask_ack = disable_8259A_irq;
293 else
294 i8259A_chip.mask_ack = mask_and_ack_8259A;
295
296 udelay(100);
297
298 outb(cached_master_mask, PIC_MASTER_IMR);
299 outb(cached_slave_mask, PIC_SLAVE_IMR);
300
301 spin_unlock_irqrestore(&i8259A_lock, flags);
302}
303
304
305
306
307static struct irqaction irq2 = {
308 .handler = no_action,
309 .name = "cascade",
310};
311
312static struct resource pic1_io_resource = {
313 .name = "pic1",
314 .start = PIC_MASTER_CMD,
315 .end = PIC_MASTER_IMR,
316 .flags = IORESOURCE_BUSY
317};
318
319static struct resource pic2_io_resource = {
320 .name = "pic2",
321 .start = PIC_SLAVE_CMD,
322 .end = PIC_SLAVE_IMR,
323 .flags = IORESOURCE_BUSY
324};
325
326
327
328
329
330
331void __init init_i8259_irqs(void)
332{
333 int i;
334
335 insert_resource(&ioport_resource, &pic1_io_resource);
336 insert_resource(&ioport_resource, &pic2_io_resource);
337
338 init_8259A(0);
339
340 for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) {
341 set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq);
342 set_irq_probe(i);
343 }
344
345 setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
346}
347