2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 1992 Linus Torvalds
7 * Copyright (C) 1994 - 2000 Ralf Baechle
9 #include <linux/delay.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
12 #include <linux/irq.h>
13 #include <linux/kernel.h>
14 #include <linux/spinlock.h>
16 #include <asm/i8259.h>
20 DEFINE_SPINLOCK(pciasic_lock
);
22 extern asmlinkage
void sni_rm200_pci_handle_int(void);
24 static void enable_pciasic_irq(unsigned int irq
)
26 unsigned int mask
= 1 << (irq
- PCIMT_IRQ_INT2
);
29 spin_lock_irqsave(&pciasic_lock
, flags
);
30 *(volatile u8
*) PCIMT_IRQSEL
|= mask
;
31 spin_unlock_irqrestore(&pciasic_lock
, flags
);
34 static unsigned int startup_pciasic_irq(unsigned int irq
)
36 enable_pciasic_irq(irq
);
37 return 0; /* never anything pending */
40 #define shutdown_pciasic_irq disable_pciasic_irq
42 void disable_pciasic_irq(unsigned int irq
)
44 unsigned int mask
= ~(1 << (irq
- PCIMT_IRQ_INT2
));
47 spin_lock_irqsave(&pciasic_lock
, flags
);
48 *(volatile u8
*) PCIMT_IRQSEL
&= mask
;
49 spin_unlock_irqrestore(&pciasic_lock
, flags
);
52 #define mask_and_ack_pciasic_irq disable_pciasic_irq
54 static void end_pciasic_irq(unsigned int irq
)
56 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
57 enable_pciasic_irq(irq
);
60 static struct hw_interrupt_type pciasic_irq_type
= {
66 mask_and_ack_pciasic_irq
,
72 * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
73 * button interrupts. Later ...
75 void pciasic_hwint0(struct pt_regs
*regs
)
77 panic("Received int0 but no handler yet ...");
80 /* This interrupt was used for the com1 console on the first prototypes. */
81 void pciasic_hwint2(struct pt_regs
*regs
)
83 /* I think this shouldn't happen on production machines. */
84 panic("hwint2 and no handler yet");
87 /* hwint5 is the r4k count / compare interrupt */
88 void pciasic_hwint5(struct pt_regs
*regs
)
90 panic("hwint5 and no handler yet");
93 static unsigned int ls1bit8(unsigned int x
)
97 s
= 4; if ((x
& 0x0f) == 0) s
= 0; b
-= s
; x
<<= s
;
98 s
= 2; if ((x
& 0x30) == 0) s
= 0; b
-= s
; x
<<= s
;
99 s
= 1; if ((x
& 0x40) == 0) s
= 0; b
-= s
;
105 * hwint 1 deals with EISA and SCSI interrupts,
107 * The EISA_INT bit in CSITPEND is high active, all others are low active.
109 void pciasic_hwint1(struct pt_regs
*regs
)
111 u8 pend
= *(volatile char *)PCIMT_CSITPEND
;
114 if (pend
& IT_EISA
) {
117 * Note: ASIC PCI's builtin interrupt achknowledge feature is
118 * broken. Using it may result in loss of some or all i8259
119 * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
122 if (unlikely(irq
< 0))
128 if (!(pend
& IT_SCSI
)) {
129 flags
= read_c0_status();
130 clear_c0_status(ST0_IM
);
131 do_IRQ(PCIMT_IRQ_SCSI
, regs
);
132 write_c0_status(flags
);
137 * hwint 3 should deal with the PCI A - D interrupts,
139 void pciasic_hwint3(struct pt_regs
*regs
)
141 u8 pend
= *(volatile char *)PCIMT_CSITPEND
;
144 pend
&= (IT_INTA
| IT_INTB
| IT_INTC
| IT_INTD
);
145 clear_c0_status(IE_IRQ3
);
146 irq
= PCIMT_IRQ_INT2
+ ls1bit8(pend
);
148 set_c0_status(IE_IRQ3
);
152 * hwint 4 is used for only the onboard PCnet 32.
154 void pciasic_hwint4(struct pt_regs
*regs
)
156 clear_c0_status(IE_IRQ4
);
157 do_IRQ(PCIMT_IRQ_ETHERNET
, regs
);
158 set_c0_status(IE_IRQ4
);
161 void __init
init_pciasic(void)
165 spin_lock_irqsave(&pciasic_lock
, flags
);
166 * (volatile u8
*) PCIMT_IRQSEL
=
167 IT_EISA
| IT_INTA
| IT_INTB
| IT_INTC
| IT_INTD
;
168 spin_unlock_irqrestore(&pciasic_lock
, flags
);
172 * On systems with i8259-style interrupt controllers we assume for
173 * driver compatibility reasons interrupts 0 - 15 to be the i8295
174 * interrupts even if the hardware uses a different interrupt numbering.
176 void __init
arch_init_irq(void)
180 set_except_vector(0, sni_rm200_pci_handle_int
);
182 init_i8259_irqs(); /* Integrated i8259 */
185 /* Actually we've got more interrupts to handle ... */
186 for (i
= PCIMT_IRQ_INT2
; i
<= PCIMT_IRQ_ETHERNET
; i
++) {
187 irq_desc
[i
].status
= IRQ_DISABLED
;
188 irq_desc
[i
].action
= 0;
189 irq_desc
[i
].depth
= 1;
190 irq_desc
[i
].handler
= &pciasic_irq_type
;
193 change_c0_status(ST0_IM
, IE_IRQ1
|IE_IRQ2
|IE_IRQ3
|IE_IRQ4
);