1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 3*1da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 4*1da177e4SLinus Torvalds * for more details. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (C) 1992 Linus Torvalds 7*1da177e4SLinus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle 8*1da177e4SLinus Torvalds */ 9*1da177e4SLinus Torvalds #include <linux/delay.h> 10*1da177e4SLinus Torvalds #include <linux/init.h> 11*1da177e4SLinus Torvalds #include <linux/interrupt.h> 12*1da177e4SLinus Torvalds #include <linux/irq.h> 13*1da177e4SLinus Torvalds #include <linux/kernel.h> 14*1da177e4SLinus Torvalds #include <linux/spinlock.h> 15*1da177e4SLinus Torvalds 16*1da177e4SLinus Torvalds #include <asm/i8259.h> 17*1da177e4SLinus Torvalds #include <asm/io.h> 18*1da177e4SLinus Torvalds #include <asm/sni.h> 19*1da177e4SLinus Torvalds 20*1da177e4SLinus Torvalds DEFINE_SPINLOCK(pciasic_lock); 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds extern asmlinkage void sni_rm200_pci_handle_int(void); 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds static void enable_pciasic_irq(unsigned int irq) 25*1da177e4SLinus Torvalds { 26*1da177e4SLinus Torvalds unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); 27*1da177e4SLinus Torvalds unsigned long flags; 28*1da177e4SLinus Torvalds 29*1da177e4SLinus Torvalds spin_lock_irqsave(&pciasic_lock, flags); 30*1da177e4SLinus Torvalds *(volatile u8 *) PCIMT_IRQSEL |= mask; 31*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pciasic_lock, flags); 32*1da177e4SLinus Torvalds } 33*1da177e4SLinus Torvalds 34*1da177e4SLinus Torvalds static unsigned int startup_pciasic_irq(unsigned int irq) 35*1da177e4SLinus Torvalds { 36*1da177e4SLinus Torvalds enable_pciasic_irq(irq); 37*1da177e4SLinus Torvalds return 0; /* never anything pending */ 38*1da177e4SLinus Torvalds } 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds #define shutdown_pciasic_irq disable_pciasic_irq 41*1da177e4SLinus Torvalds 42*1da177e4SLinus Torvalds void disable_pciasic_irq(unsigned int irq) 43*1da177e4SLinus Torvalds { 44*1da177e4SLinus Torvalds unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2)); 45*1da177e4SLinus Torvalds unsigned long flags; 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds spin_lock_irqsave(&pciasic_lock, flags); 48*1da177e4SLinus Torvalds *(volatile u8 *) PCIMT_IRQSEL &= mask; 49*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pciasic_lock, flags); 50*1da177e4SLinus Torvalds } 51*1da177e4SLinus Torvalds 52*1da177e4SLinus Torvalds #define mask_and_ack_pciasic_irq disable_pciasic_irq 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds static void end_pciasic_irq(unsigned int irq) 55*1da177e4SLinus Torvalds { 56*1da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 57*1da177e4SLinus Torvalds enable_pciasic_irq(irq); 58*1da177e4SLinus Torvalds } 59*1da177e4SLinus Torvalds 60*1da177e4SLinus Torvalds static struct hw_interrupt_type pciasic_irq_type = { 61*1da177e4SLinus Torvalds "ASIC-PCI", 62*1da177e4SLinus Torvalds startup_pciasic_irq, 63*1da177e4SLinus Torvalds shutdown_pciasic_irq, 64*1da177e4SLinus Torvalds enable_pciasic_irq, 65*1da177e4SLinus Torvalds disable_pciasic_irq, 66*1da177e4SLinus Torvalds mask_and_ack_pciasic_irq, 67*1da177e4SLinus Torvalds end_pciasic_irq, 68*1da177e4SLinus Torvalds NULL 69*1da177e4SLinus Torvalds }; 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* 72*1da177e4SLinus Torvalds * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug 73*1da177e4SLinus Torvalds * button interrupts. Later ... 74*1da177e4SLinus Torvalds */ 75*1da177e4SLinus Torvalds void pciasic_hwint0(struct pt_regs *regs) 76*1da177e4SLinus Torvalds { 77*1da177e4SLinus Torvalds panic("Received int0 but no handler yet ..."); 78*1da177e4SLinus Torvalds } 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds /* This interrupt was used for the com1 console on the first prototypes. */ 81*1da177e4SLinus Torvalds void pciasic_hwint2(struct pt_regs *regs) 82*1da177e4SLinus Torvalds { 83*1da177e4SLinus Torvalds /* I think this shouldn't happen on production machines. */ 84*1da177e4SLinus Torvalds panic("hwint2 and no handler yet"); 85*1da177e4SLinus Torvalds } 86*1da177e4SLinus Torvalds 87*1da177e4SLinus Torvalds /* hwint5 is the r4k count / compare interrupt */ 88*1da177e4SLinus Torvalds void pciasic_hwint5(struct pt_regs *regs) 89*1da177e4SLinus Torvalds { 90*1da177e4SLinus Torvalds panic("hwint5 and no handler yet"); 91*1da177e4SLinus Torvalds } 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds static unsigned int ls1bit8(unsigned int x) 94*1da177e4SLinus Torvalds { 95*1da177e4SLinus Torvalds int b = 7, s; 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s; 98*1da177e4SLinus Torvalds s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s; 99*1da177e4SLinus Torvalds s = 1; if ((x & 0x40) == 0) s = 0; b -= s; 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds return b; 102*1da177e4SLinus Torvalds } 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds /* 105*1da177e4SLinus Torvalds * hwint 1 deals with EISA and SCSI interrupts, 106*1da177e4SLinus Torvalds * 107*1da177e4SLinus Torvalds * The EISA_INT bit in CSITPEND is high active, all others are low active. 108*1da177e4SLinus Torvalds */ 109*1da177e4SLinus Torvalds void pciasic_hwint1(struct pt_regs *regs) 110*1da177e4SLinus Torvalds { 111*1da177e4SLinus Torvalds u8 pend = *(volatile char *)PCIMT_CSITPEND; 112*1da177e4SLinus Torvalds unsigned long flags; 113*1da177e4SLinus Torvalds 114*1da177e4SLinus Torvalds if (pend & IT_EISA) { 115*1da177e4SLinus Torvalds int irq; 116*1da177e4SLinus Torvalds /* 117*1da177e4SLinus Torvalds * Note: ASIC PCI's builtin interrupt achknowledge feature is 118*1da177e4SLinus Torvalds * broken. Using it may result in loss of some or all i8259 119*1da177e4SLinus Torvalds * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ... 120*1da177e4SLinus Torvalds */ 121*1da177e4SLinus Torvalds irq = i8259_irq(); 122*1da177e4SLinus Torvalds if (unlikely(irq < 0)) 123*1da177e4SLinus Torvalds return; 124*1da177e4SLinus Torvalds 125*1da177e4SLinus Torvalds do_IRQ(irq, regs); 126*1da177e4SLinus Torvalds } 127*1da177e4SLinus Torvalds 128*1da177e4SLinus Torvalds if (!(pend & IT_SCSI)) { 129*1da177e4SLinus Torvalds flags = read_c0_status(); 130*1da177e4SLinus Torvalds clear_c0_status(ST0_IM); 131*1da177e4SLinus Torvalds do_IRQ(PCIMT_IRQ_SCSI, regs); 132*1da177e4SLinus Torvalds write_c0_status(flags); 133*1da177e4SLinus Torvalds } 134*1da177e4SLinus Torvalds } 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds /* 137*1da177e4SLinus Torvalds * hwint 3 should deal with the PCI A - D interrupts, 138*1da177e4SLinus Torvalds */ 139*1da177e4SLinus Torvalds void pciasic_hwint3(struct pt_regs *regs) 140*1da177e4SLinus Torvalds { 141*1da177e4SLinus Torvalds u8 pend = *(volatile char *)PCIMT_CSITPEND; 142*1da177e4SLinus Torvalds int irq; 143*1da177e4SLinus Torvalds 144*1da177e4SLinus Torvalds pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); 145*1da177e4SLinus Torvalds clear_c0_status(IE_IRQ3); 146*1da177e4SLinus Torvalds irq = PCIMT_IRQ_INT2 + ls1bit8(pend); 147*1da177e4SLinus Torvalds do_IRQ(irq, regs); 148*1da177e4SLinus Torvalds set_c0_status(IE_IRQ3); 149*1da177e4SLinus Torvalds } 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds /* 152*1da177e4SLinus Torvalds * hwint 4 is used for only the onboard PCnet 32. 153*1da177e4SLinus Torvalds */ 154*1da177e4SLinus Torvalds void pciasic_hwint4(struct pt_regs *regs) 155*1da177e4SLinus Torvalds { 156*1da177e4SLinus Torvalds clear_c0_status(IE_IRQ4); 157*1da177e4SLinus Torvalds do_IRQ(PCIMT_IRQ_ETHERNET, regs); 158*1da177e4SLinus Torvalds set_c0_status(IE_IRQ4); 159*1da177e4SLinus Torvalds } 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds void __init init_pciasic(void) 162*1da177e4SLinus Torvalds { 163*1da177e4SLinus Torvalds unsigned long flags; 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds spin_lock_irqsave(&pciasic_lock, flags); 166*1da177e4SLinus Torvalds * (volatile u8 *) PCIMT_IRQSEL = 167*1da177e4SLinus Torvalds IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD; 168*1da177e4SLinus Torvalds spin_unlock_irqrestore(&pciasic_lock, flags); 169*1da177e4SLinus Torvalds } 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds /* 172*1da177e4SLinus Torvalds * On systems with i8259-style interrupt controllers we assume for 173*1da177e4SLinus Torvalds * driver compatibility reasons interrupts 0 - 15 to be the i8295 174*1da177e4SLinus Torvalds * interrupts even if the hardware uses a different interrupt numbering. 175*1da177e4SLinus Torvalds */ 176*1da177e4SLinus Torvalds void __init arch_init_irq(void) 177*1da177e4SLinus Torvalds { 178*1da177e4SLinus Torvalds int i; 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds set_except_vector(0, sni_rm200_pci_handle_int); 181*1da177e4SLinus Torvalds 182*1da177e4SLinus Torvalds init_i8259_irqs(); /* Integrated i8259 */ 183*1da177e4SLinus Torvalds init_pciasic(); 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds /* Actually we've got more interrupts to handle ... */ 186*1da177e4SLinus Torvalds for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++) { 187*1da177e4SLinus Torvalds irq_desc[i].status = IRQ_DISABLED; 188*1da177e4SLinus Torvalds irq_desc[i].action = 0; 189*1da177e4SLinus Torvalds irq_desc[i].depth = 1; 190*1da177e4SLinus Torvalds irq_desc[i].handler = &pciasic_irq_type; 191*1da177e4SLinus Torvalds } 192*1da177e4SLinus Torvalds 193*1da177e4SLinus Torvalds change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4); 194*1da177e4SLinus Torvalds } 195