Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / ppc / syslib / ppc8xx_pic.c
1 #include <linux/config.h>
2 #include <linux/module.h>
3 #include <linux/stddef.h>
4 #include <linux/init.h>
5 #include <linux/sched.h>
6 #include <linux/signal.h>
7 #include <linux/interrupt.h>
8 #include <asm/irq.h>
9 #include <asm/io.h>
10 #include <asm/8xx_immap.h>
11 #include <asm/mpc8xx.h>
12 #include "ppc8xx_pic.h"
13
14 extern int cpm_get_irq(struct pt_regs *regs);
15
16 /* The 8xx internal interrupt controller.  It is usually
17  * the only interrupt controller.  Some boards, like the MBX and
18  * Sandpoint have the 8259 as a secondary controller.  Depending
19  * upon the processor type, the internal controller can have as
20  * few as 16 interrups or as many as 64.  We could use  the
21  * "clear_bit()" and "set_bit()" functions like other platforms,
22  * but they are overkill for us.
23  */
24
25 static void m8xx_mask_irq(unsigned int irq_nr)
26 {
27         int     bit, word;
28
29         bit = irq_nr & 0x1f;
30         word = irq_nr >> 5;
31
32         ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
33         out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
34 }
35
36 static void m8xx_unmask_irq(unsigned int irq_nr)
37 {
38         int     bit, word;
39
40         bit = irq_nr & 0x1f;
41         word = irq_nr >> 5;
42
43         ppc_cached_irq_mask[word] |= (1 << (31-bit));
44         out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
45 }
46
47 static void m8xx_end_irq(unsigned int irq_nr)
48 {
49         if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
50                         && irq_desc[irq_nr].action) {
51                 int bit, word;
52
53                 bit = irq_nr & 0x1f;
54                 word = irq_nr >> 5;
55
56                 ppc_cached_irq_mask[word] |= (1 << (31-bit));
57                 out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
58         }
59 }
60
61
62 static void m8xx_mask_and_ack(unsigned int irq_nr)
63 {
64         int     bit, word;
65
66         bit = irq_nr & 0x1f;
67         word = irq_nr >> 5;
68
69         ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
70         out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
71         out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend, 1 << (31-bit));
72 }
73
74 struct hw_interrupt_type ppc8xx_pic = {
75         .typename = " 8xx SIU  ",
76         .enable = m8xx_unmask_irq,
77         .disable = m8xx_mask_irq,
78         .ack = m8xx_mask_and_ack,
79         .end = m8xx_end_irq,
80 };
81
82 /*
83  * We either return a valid interrupt or -1 if there is nothing pending
84  */
85 int
86 m8xx_get_irq(struct pt_regs *regs)
87 {
88         int irq;
89
90         /* For MPC8xx, read the SIVEC register and shift the bits down
91          * to get the irq number.
92          */
93         irq = in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec) >> 26;
94
95         /*
96          * When we read the sivec without an interrupt to process, we will
97          * get back SIU_LEVEL7.  In this case, return -1
98          */
99         if (irq == CPM_INTERRUPT)
100                 irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
101 #if defined(CONFIG_PCI)
102         else if (irq == ISA_BRIDGE_INT) {
103                 int isa_irq;
104
105                 if ((isa_irq = i8259_poll(regs)) >= 0)
106                         irq = I8259_IRQ_OFFSET + isa_irq;
107         }
108 #endif  /* CONFIG_PCI */
109         else if (irq == SIU_LEVEL7)
110                 irq = -1;
111
112         return irq;
113 }
114
115 #if defined(CONFIG_MBX) && defined(CONFIG_PCI)
116 /* Only the MBX uses the external 8259.  This allows us to catch standard
117  * drivers that may mess up the internal interrupt controllers, and also
118  * allow them to run without modification on the MBX.
119  */
120 void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
121 {
122         /* This interrupt handler never actually gets called.  It is
123          * installed only to unmask the 8259 cascade interrupt in the SIU
124          * and to make the 8259 cascade interrupt visible in /proc/interrupts.
125          */
126 }
127 #endif  /* CONFIG_PCI */