2 * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
4 * Copyright (C) 1997 Geert Uytterhoeven
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
11 #include <linux/config.h>
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/irq.h>
16 #include <linux/smp.h>
17 #include <linux/interrupt.h>
18 #include <asm/ptrace.h>
19 #include <asm/signal.h>
21 #include <asm/pgtable.h>
25 #include <asm/machdep.h>
28 #include "open_pic_defs.h"
31 static volatile struct OpenPIC *OpenPIC2 = NULL;
33 extern u_int OpenPIC_NumInitSenses;
34 extern u_char *OpenPIC_InitSenses;
36 static u_int NumSources;
38 static int open_pic2_irq_offset;
40 static OpenPIC_SourcePtr ISU2[OPENPIC_MAX_ISU];
42 unsigned int openpic2_vec_spurious;
45 * Accesses to the current processor's openpic registers
46 * U3 secondary openpic has only one output
48 #define THIS_CPU Processor[0]
50 #define CHECK_THIS_CPU
52 #define GET_ISU(source) ISU2[(source) >> 4][(source) & 0xf]
54 static inline u_int openpic2_read(volatile u_int *addr)
62 static inline void openpic2_write(volatile u_int *addr, u_int val)
67 static inline u_int openpic2_readfield(volatile u_int *addr, u_int mask)
69 u_int val = openpic2_read(addr);
73 static inline void openpic2_writefield(volatile u_int *addr, u_int mask,
76 u_int val = openpic2_read(addr);
77 openpic2_write(addr, (val & ~mask) | (field & mask));
80 static inline void openpic2_clearfield(volatile u_int *addr, u_int mask)
82 openpic2_writefield(addr, mask, 0);
85 static inline void openpic2_setfield(volatile u_int *addr, u_int mask)
87 openpic2_writefield(addr, mask, mask);
90 static void openpic2_safe_writefield(volatile u_int *addr, u_int mask,
93 unsigned int loops = 100000;
95 openpic2_setfield(addr, OPENPIC_MASK);
96 while (openpic2_read(addr) & OPENPIC_ACTIVITY) {
98 printk(KERN_ERR "openpic2_safe_writefield timeout\n");
102 openpic2_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
106 static inline void openpic2_reset(void)
108 openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
109 OPENPIC_CONFIG_RESET);
112 static void openpic2_disable_8259_pass_through(void)
114 openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
115 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
119 * Find out the current interrupt
121 static u_int openpic2_irq(void)
126 vec = openpic2_readfield(&OpenPIC2->THIS_CPU.Interrupt_Acknowledge,
127 OPENPIC_VECTOR_MASK);
131 static void openpic2_eoi(void)
135 openpic2_write(&OpenPIC2->THIS_CPU.EOI, 0);
136 /* Handle PCI write posting */
137 (void)openpic2_read(&OpenPIC2->THIS_CPU.EOI);
141 static inline u_int openpic2_get_priority(void)
145 return openpic2_readfield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
146 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
149 static void openpic2_set_priority(u_int pri)
153 openpic2_writefield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
154 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
158 * Get/set the spurious vector
160 static inline u_int openpic2_get_spurious(void)
162 return openpic2_readfield(&OpenPIC2->Global.Spurious_Vector,
163 OPENPIC_VECTOR_MASK);
166 static void openpic2_set_spurious(u_int vec)
168 openpic2_writefield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
173 * Enable/disable an external interrupt source
175 * Externally called, irq is an offseted system-wide interrupt number
177 static void openpic2_enable_irq(u_int irq)
179 unsigned int loops = 100000;
181 openpic2_clearfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority, OPENPIC_MASK);
182 /* make sure mask gets to controller before we return to user */
185 printk(KERN_ERR "openpic_enable_irq timeout\n");
189 mb(); /* sync is probably useless here */
190 } while(openpic2_readfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority,
194 static void openpic2_disable_irq(u_int irq)
197 unsigned int loops = 100000;
199 openpic2_setfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority,
201 /* make sure mask gets to controller before we return to user */
204 printk(KERN_ERR "openpic_disable_irq timeout\n");
208 mb(); /* sync is probably useless here */
209 vp = openpic2_readfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority,
210 OPENPIC_MASK | OPENPIC_ACTIVITY);
211 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
215 * Initialize an interrupt source (and disable it!)
217 * irq: OpenPIC interrupt number
218 * pri: interrupt source priority
219 * vec: the vector it will produce
220 * pol: polarity (1 for positive, 0 for negative)
221 * sense: 1 for level, 0 for edge
223 static void openpic2_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
225 openpic2_safe_writefield(&GET_ISU(irq).Vector_Priority,
226 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
227 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
228 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
229 (pol ? OPENPIC_POLARITY_POSITIVE :
230 OPENPIC_POLARITY_NEGATIVE) |
231 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
235 * Map an interrupt source to one or more CPUs
237 static void openpic2_mapirq(u_int irq, u_int physmask)
239 openpic2_write(&GET_ISU(irq).Destination, physmask);
243 * Set the sense for an interrupt source (and disable it!)
245 * sense: 1 for level, 0 for edge
247 static inline void openpic2_set_sense(u_int irq, int sense)
249 openpic2_safe_writefield(&GET_ISU(irq).Vector_Priority,
251 (sense ? OPENPIC_SENSE_LEVEL : 0));
254 static void openpic2_end_irq(unsigned int irq_nr)
259 int openpic2_get_irq(struct pt_regs *regs)
261 int irq = openpic2_irq();
263 if (irq == openpic2_vec_spurious)
265 return irq + open_pic2_irq_offset;
268 struct hw_interrupt_type open_pic2 = {
273 openpic2_disable_irq,
278 void __init openpic2_init(int offset)
283 if (!OpenPIC2_Addr) {
284 printk(KERN_INFO "No OpenPIC2 found !\n");
287 OpenPIC2 = (volatile struct OpenPIC *)OpenPIC2_Addr;
289 ppc64_boot_msg(0x20, "OpenPic U3 Init");
291 t = openpic2_read(&OpenPIC2->Global.Feature_Reporting0);
292 switch (t & OPENPIC_FEATURE_VERSION_MASK) {
306 printk(KERN_INFO "OpenPIC (U3) Version %s\n", version);
308 open_pic2_irq_offset = offset;
310 for (i=0; i<128; i+=0x10) {
311 ISU2[i>>4] = &((struct OpenPIC *)OpenPIC2_Addr)->Source[i];
314 NumSources = NumISUs * 0x10;
315 openpic2_vec_spurious = NumSources;
317 openpic2_set_priority(0xf);
319 /* Init all external sources */
320 for (i = 0; i < NumSources; i++) {
323 /* the bootloader may have left it enabled (bad !) */
324 openpic2_disable_irq(i+offset);
327 sense = (i < OpenPIC_NumInitSenses) ? OpenPIC_InitSenses[i]: 1;
329 irq_desc[i+offset].status = IRQ_LEVEL;
331 /* Enabled, Priority 8 or 9 */
332 openpic2_initirq(i, pri, i, !sense, sense);
334 openpic2_mapirq(i, 0x1);
337 /* Init descriptors */
338 for (i = offset; i < NumSources + offset; i++)
339 irq_desc[i].handler = &open_pic2;
341 /* Initialize the spurious interrupt */
342 openpic2_set_spurious(openpic2_vec_spurious);
344 openpic2_set_priority(0);
345 openpic2_disable_8259_pass_through();
347 ppc64_boot_msg(0x25, "OpenPic U3 Done");