diff options
Diffstat (limited to 'arch/mips/mips-boards/malta/malta_int.c')
-rw-r--r-- | arch/mips/mips-boards/malta/malta_int.c | 153 |
1 files changed, 109 insertions, 44 deletions
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index dd2db35966bc..d06dc5ad6c9e 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/random.h> | 30 | #include <linux/random.h> |
31 | 31 | ||
32 | #include <asm/i8259.h> | 32 | #include <asm/i8259.h> |
33 | #include <asm/irq_cpu.h> | ||
33 | #include <asm/io.h> | 34 | #include <asm/io.h> |
34 | #include <asm/mips-boards/malta.h> | 35 | #include <asm/mips-boards/malta.h> |
35 | #include <asm/mips-boards/maltaint.h> | 36 | #include <asm/mips-boards/maltaint.h> |
@@ -37,8 +38,10 @@ | |||
37 | #include <asm/gt64120.h> | 38 | #include <asm/gt64120.h> |
38 | #include <asm/mips-boards/generic.h> | 39 | #include <asm/mips-boards/generic.h> |
39 | #include <asm/mips-boards/msc01_pci.h> | 40 | #include <asm/mips-boards/msc01_pci.h> |
41 | #include <asm/msc01_ic.h> | ||
40 | 42 | ||
41 | extern asmlinkage void mipsIRQ(void); | 43 | extern asmlinkage void mipsIRQ(void); |
44 | extern void mips_timer_interrupt(void); | ||
42 | 45 | ||
43 | static DEFINE_SPINLOCK(mips_irq_lock); | 46 | static DEFINE_SPINLOCK(mips_irq_lock); |
44 | 47 | ||
@@ -54,6 +57,7 @@ static inline int mips_pcibios_iack(void) | |||
54 | switch(mips_revision_corid) { | 57 | switch(mips_revision_corid) { |
55 | case MIPS_REVISION_CORID_CORE_MSC: | 58 | case MIPS_REVISION_CORID_CORE_MSC: |
56 | case MIPS_REVISION_CORID_CORE_FPGA2: | 59 | case MIPS_REVISION_CORID_CORE_FPGA2: |
60 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
57 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | 61 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: |
58 | MSC_READ(MSC01_PCI_IACK, irq); | 62 | MSC_READ(MSC01_PCI_IACK, irq); |
59 | irq &= 0xff; | 63 | irq &= 0xff; |
@@ -91,88 +95,86 @@ static inline int mips_pcibios_iack(void) | |||
91 | return irq; | 95 | return irq; |
92 | } | 96 | } |
93 | 97 | ||
94 | static inline int get_int(int *irq) | 98 | static inline int get_int(void) |
95 | { | 99 | { |
96 | unsigned long flags; | 100 | unsigned long flags; |
97 | 101 | int irq; | |
98 | spin_lock_irqsave(&mips_irq_lock, flags); | 102 | spin_lock_irqsave(&mips_irq_lock, flags); |
99 | 103 | ||
100 | *irq = mips_pcibios_iack(); | 104 | irq = mips_pcibios_iack(); |
101 | 105 | ||
102 | /* | 106 | /* |
103 | * IRQ7 is used to detect spurious interrupts. | 107 | * The only way we can decide if an interrupt is spurious |
104 | * The interrupt acknowledge cycle returns IRQ7, if no | 108 | * is by checking the 8259 registers. This needs a spinlock |
105 | * interrupts is requested. | 109 | * on an SMP system, so leave it up to the generic code... |
106 | * We can differentiate between this situation and a | ||
107 | * "Normal" IRQ7 by reading the ISR. | ||
108 | */ | 110 | */ |
109 | if (*irq == 7) | ||
110 | { | ||
111 | outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, | ||
112 | PIIX4_ICTLR1_OCW3); | ||
113 | if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) { | ||
114 | spin_unlock_irqrestore(&mips_irq_lock, flags); | ||
115 | printk("We got a spurious interrupt from PIIX4.\n"); | ||
116 | atomic_inc(&irq_err_count); | ||
117 | return -1; /* Spurious interrupt. */ | ||
118 | } | ||
119 | } | ||
120 | 111 | ||
121 | spin_unlock_irqrestore(&mips_irq_lock, flags); | 112 | spin_unlock_irqrestore(&mips_irq_lock, flags); |
122 | 113 | ||
123 | return 0; | 114 | return irq; |
124 | } | 115 | } |
125 | 116 | ||
126 | void malta_hw0_irqdispatch(struct pt_regs *regs) | 117 | void malta_hw0_irqdispatch(struct pt_regs *regs) |
127 | { | 118 | { |
128 | int irq; | 119 | int irq; |
129 | 120 | ||
130 | if (get_int(&irq)) | 121 | irq = get_int(); |
131 | return; /* interrupt has already been cleared */ | 122 | if (irq < 0) |
123 | return; /* interrupt has already been cleared */ | ||
132 | 124 | ||
133 | do_IRQ(irq, regs); | 125 | do_IRQ(MALTA_INT_BASE+irq, regs); |
134 | } | 126 | } |
135 | 127 | ||
136 | void corehi_irqdispatch(struct pt_regs *regs) | 128 | void corehi_irqdispatch(struct pt_regs *regs) |
137 | { | 129 | { |
138 | unsigned int data,datahi; | 130 | unsigned int intrcause,datalo,datahi; |
139 | 131 | unsigned int pcimstat, intisr, inten, intpol, intedge, intsteer, pcicmd, pcibadaddr; | |
140 | /* Mask out corehi interrupt. */ | ||
141 | clear_c0_status(IE_IRQ3); | ||
142 | 132 | ||
143 | printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n"); | 133 | printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n"); |
144 | printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n" | 134 | printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n" |
145 | , regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr); | 135 | , regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr); |
136 | |||
137 | /* Read all the registers and then print them as there is a | ||
138 | problem with interspersed printk's upsetting the Bonito controller. | ||
139 | Do it for the others too. | ||
140 | */ | ||
141 | |||
146 | switch(mips_revision_corid) { | 142 | switch(mips_revision_corid) { |
147 | case MIPS_REVISION_CORID_CORE_MSC: | 143 | case MIPS_REVISION_CORID_CORE_MSC: |
148 | case MIPS_REVISION_CORID_CORE_FPGA2: | 144 | case MIPS_REVISION_CORID_CORE_FPGA2: |
149 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | 145 | case MIPS_REVISION_CORID_CORE_FPGA3: |
146 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | ||
147 | ll_msc_irq(regs); | ||
150 | break; | 148 | break; |
151 | case MIPS_REVISION_CORID_QED_RM5261: | 149 | case MIPS_REVISION_CORID_QED_RM5261: |
152 | case MIPS_REVISION_CORID_CORE_LV: | 150 | case MIPS_REVISION_CORID_CORE_LV: |
153 | case MIPS_REVISION_CORID_CORE_FPGA: | 151 | case MIPS_REVISION_CORID_CORE_FPGA: |
154 | case MIPS_REVISION_CORID_CORE_FPGAR2: | 152 | case MIPS_REVISION_CORID_CORE_FPGAR2: |
155 | data = GT_READ(GT_INTRCAUSE_OFS); | 153 | intrcause = GT_READ(GT_INTRCAUSE_OFS); |
156 | printk("GT_INTRCAUSE = %08x\n", data); | 154 | datalo = GT_READ(GT_CPUERR_ADDRLO_OFS); |
157 | data = GT_READ(GT_CPUERR_ADDRLO_OFS); | ||
158 | datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); | 155 | datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); |
159 | printk("GT_CPUERR_ADDR = %02x%08x\n", datahi, data); | 156 | printk("GT_INTRCAUSE = %08x\n", intrcause); |
157 | printk("GT_CPUERR_ADDR = %02x%08x\n", datahi, datalo); | ||
160 | break; | 158 | break; |
161 | case MIPS_REVISION_CORID_BONITO64: | 159 | case MIPS_REVISION_CORID_BONITO64: |
162 | case MIPS_REVISION_CORID_CORE_20K: | 160 | case MIPS_REVISION_CORID_CORE_20K: |
163 | case MIPS_REVISION_CORID_CORE_EMUL_BON: | 161 | case MIPS_REVISION_CORID_CORE_EMUL_BON: |
164 | data = BONITO_INTISR; | 162 | pcibadaddr = BONITO_PCIBADADDR; |
165 | printk("BONITO_INTISR = %08x\n", data); | 163 | pcimstat = BONITO_PCIMSTAT; |
166 | data = BONITO_INTEN; | 164 | intisr = BONITO_INTISR; |
167 | printk("BONITO_INTEN = %08x\n", data); | 165 | inten = BONITO_INTEN; |
168 | data = BONITO_INTPOL; | 166 | intpol = BONITO_INTPOL; |
169 | printk("BONITO_INTPOL = %08x\n", data); | 167 | intedge = BONITO_INTEDGE; |
170 | data = BONITO_INTEDGE; | 168 | intsteer = BONITO_INTSTEER; |
171 | printk("BONITO_INTEDGE = %08x\n", data); | 169 | pcicmd = BONITO_PCICMD; |
172 | data = BONITO_INTSTEER; | 170 | printk("BONITO_INTISR = %08x\n", intisr); |
173 | printk("BONITO_INTSTEER = %08x\n", data); | 171 | printk("BONITO_INTEN = %08x\n", inten); |
174 | data = BONITO_PCICMD; | 172 | printk("BONITO_INTPOL = %08x\n", intpol); |
175 | printk("BONITO_PCICMD = %08x\n", data); | 173 | printk("BONITO_INTEDGE = %08x\n", intedge); |
174 | printk("BONITO_INTSTEER = %08x\n", intsteer); | ||
175 | printk("BONITO_PCICMD = %08x\n", pcicmd); | ||
176 | printk("BONITO_PCIBADADDR = %08x\n", pcibadaddr); | ||
177 | printk("BONITO_PCIMSTAT = %08x\n", pcimstat); | ||
176 | break; | 178 | break; |
177 | } | 179 | } |
178 | 180 | ||
@@ -180,8 +182,71 @@ void corehi_irqdispatch(struct pt_regs *regs) | |||
180 | die("CoreHi interrupt", regs); | 182 | die("CoreHi interrupt", regs); |
181 | } | 183 | } |
182 | 184 | ||
185 | static struct irqaction i8259irq = { | ||
186 | .handler = no_action, | ||
187 | .name = "XT-PIC cascade" | ||
188 | }; | ||
189 | |||
190 | static struct irqaction corehi_irqaction = { | ||
191 | .handler = no_action, | ||
192 | .name = "CoreHi" | ||
193 | }; | ||
194 | |||
195 | msc_irqmap_t __initdata msc_irqmap[] = { | ||
196 | {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
197 | {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
198 | }; | ||
199 | int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t); | ||
200 | |||
201 | msc_irqmap_t __initdata msc_eicirqmap[] = { | ||
202 | {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, | ||
203 | {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, | ||
204 | {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, | ||
205 | {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0}, | ||
206 | {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0}, | ||
207 | {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0}, | ||
208 | {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, | ||
209 | {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, | ||
210 | {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, | ||
211 | {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} | ||
212 | }; | ||
213 | int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t); | ||
214 | |||
183 | void __init arch_init_irq(void) | 215 | void __init arch_init_irq(void) |
184 | { | 216 | { |
185 | set_except_vector(0, mipsIRQ); | 217 | set_except_vector(0, mipsIRQ); |
186 | init_i8259_irqs(); | 218 | init_i8259_irqs(); |
219 | |||
220 | if (!cpu_has_veic) | ||
221 | mips_cpu_irq_init (MIPSCPU_INT_BASE); | ||
222 | |||
223 | switch(mips_revision_corid) { | ||
224 | case MIPS_REVISION_CORID_CORE_MSC: | ||
225 | case MIPS_REVISION_CORID_CORE_FPGA2: | ||
226 | case MIPS_REVISION_CORID_CORE_FPGA3: | ||
227 | case MIPS_REVISION_CORID_CORE_EMUL_MSC: | ||
228 | if (cpu_has_veic) | ||
229 | init_msc_irqs (MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); | ||
230 | else | ||
231 | init_msc_irqs (MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); | ||
232 | } | ||
233 | |||
234 | if (cpu_has_veic) { | ||
235 | set_vi_handler (MSC01E_INT_I8259A, malta_hw0_irqdispatch); | ||
236 | set_vi_handler (MSC01E_INT_COREHI, corehi_irqdispatch); | ||
237 | setup_irq (MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq); | ||
238 | setup_irq (MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction); | ||
239 | } | ||
240 | else if (cpu_has_vint) { | ||
241 | set_vi_handler (MIPSCPU_INT_I8259A, malta_hw0_irqdispatch); | ||
242 | set_vi_handler (MIPSCPU_INT_COREHI, corehi_irqdispatch); | ||
243 | |||
244 | setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); | ||
245 | setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); | ||
246 | } | ||
247 | else { | ||
248 | set_except_vector(0, mipsIRQ); | ||
249 | setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_I8259A, &i8259irq); | ||
250 | setup_irq (MIPSCPU_INT_BASE+MIPSCPU_INT_COREHI, &corehi_irqaction); | ||
251 | } | ||
187 | } | 252 | } |