1 /* 2 * i8259 interrupt controller driver. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 #include <linux/init.h> 10 #include <linux/ioport.h> 11 #include <linux/interrupt.h> 12 #include <asm/io.h> 13 #include <asm/i8259.h> 14 15 static volatile void __iomem *pci_intack; /* RO, gives us the irq vector */ 16 17 static unsigned char cached_8259[2] = { 0xff, 0xff }; 18 #define cached_A1 (cached_8259[0]) 19 #define cached_21 (cached_8259[1]) 20 21 static DEFINE_SPINLOCK(i8259_lock); 22 23 static int i8259_pic_irq_offset; 24 25 /* 26 * Acknowledge the IRQ using either the PCI host bridge's interrupt 27 * acknowledge feature or poll. How i8259_init() is called determines 28 * which is called. It should be noted that polling is broken on some 29 * IBM and Motorola PReP boxes so we must use the int-ack feature on them. 30 */ 31 int i8259_irq(struct pt_regs *regs) 32 { 33 int irq; 34 35 spin_lock(&i8259_lock); 36 37 /* Either int-ack or poll for the IRQ */ 38 if (pci_intack) 39 irq = readb(pci_intack); 40 else { 41 /* Perform an interrupt acknowledge cycle on controller 1. */ 42 outb(0x0C, 0x20); /* prepare for poll */ 43 irq = inb(0x20) & 7; 44 if (irq == 2 ) { 45 /* 46 * Interrupt is cascaded so perform interrupt 47 * acknowledge on controller 2. 48 */ 49 outb(0x0C, 0xA0); /* prepare for poll */ 50 irq = (inb(0xA0) & 7) + 8; 51 } 52 } 53 54 if (irq == 7) { 55 /* 56 * This may be a spurious interrupt. 57 * 58 * Read the interrupt status register (ISR). If the most 59 * significant bit is not set then there is no valid 60 * interrupt. 61 */ 62 if (!pci_intack) 63 outb(0x0B, 0x20); /* ISR register */ 64 if(~inb(0x20) & 0x80) 65 irq = -1; 66 } 67 68 spin_unlock(&i8259_lock); 69 return irq + i8259_pic_irq_offset; 70 } 71 72 int i8259_irq_cascade(struct pt_regs *regs, void *unused) 73 { 74 return i8259_irq(regs); 75 } 76 77 static void i8259_mask_and_ack_irq(unsigned int irq_nr) 78 { 79 unsigned long flags; 80 81 spin_lock_irqsave(&i8259_lock, flags); 82 irq_nr -= i8259_pic_irq_offset; 83 if (irq_nr > 7) { 84 cached_A1 |= 1 << (irq_nr-8); 85 inb(0xA1); /* DUMMY */ 86 outb(cached_A1, 0xA1); 87 outb(0x20, 0xA0); /* Non-specific EOI */ 88 outb(0x20, 0x20); /* Non-specific EOI to cascade */ 89 } else { 90 cached_21 |= 1 << irq_nr; 91 inb(0x21); /* DUMMY */ 92 outb(cached_21, 0x21); 93 outb(0x20, 0x20); /* Non-specific EOI */ 94 } 95 spin_unlock_irqrestore(&i8259_lock, flags); 96 } 97 98 static void i8259_set_irq_mask(int irq_nr) 99 { 100 outb(cached_A1,0xA1); 101 outb(cached_21,0x21); 102 } 103 104 static void i8259_mask_irq(unsigned int irq_nr) 105 { 106 unsigned long flags; 107 108 spin_lock_irqsave(&i8259_lock, flags); 109 irq_nr -= i8259_pic_irq_offset; 110 if (irq_nr < 8) 111 cached_21 |= 1 << irq_nr; 112 else 113 cached_A1 |= 1 << (irq_nr-8); 114 i8259_set_irq_mask(irq_nr); 115 spin_unlock_irqrestore(&i8259_lock, flags); 116 } 117 118 static void i8259_unmask_irq(unsigned int irq_nr) 119 { 120 unsigned long flags; 121 122 spin_lock_irqsave(&i8259_lock, flags); 123 irq_nr -= i8259_pic_irq_offset; 124 if (irq_nr < 8) 125 cached_21 &= ~(1 << irq_nr); 126 else 127 cached_A1 &= ~(1 << (irq_nr-8)); 128 i8259_set_irq_mask(irq_nr); 129 spin_unlock_irqrestore(&i8259_lock, flags); 130 } 131 132 static void i8259_end_irq(unsigned int irq) 133 { 134 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) 135 && irq_desc[irq].action) 136 i8259_unmask_irq(irq); 137 } 138 139 struct hw_interrupt_type i8259_pic = { 140 .typename = " i8259 ", 141 .enable = i8259_unmask_irq, 142 .disable = i8259_mask_irq, 143 .ack = i8259_mask_and_ack_irq, 144 .end = i8259_end_irq, 145 }; 146 147 static struct resource pic1_iores = { 148 .name = "8259 (master)", 149 .start = 0x20, 150 .end = 0x21, 151 .flags = IORESOURCE_BUSY, 152 }; 153 154 static struct resource pic2_iores = { 155 .name = "8259 (slave)", 156 .start = 0xa0, 157 .end = 0xa1, 158 .flags = IORESOURCE_BUSY, 159 }; 160 161 static struct resource pic_edgectrl_iores = { 162 .name = "8259 edge control", 163 .start = 0x4d0, 164 .end = 0x4d1, 165 .flags = IORESOURCE_BUSY, 166 }; 167 168 static struct irqaction i8259_irqaction = { 169 .handler = no_action, 170 .flags = SA_INTERRUPT, 171 .mask = CPU_MASK_NONE, 172 .name = "82c59 secondary cascade", 173 }; 174 175 /* 176 * i8259_init() 177 * intack_addr - PCI interrupt acknowledge (real) address which will return 178 * the active irq from the 8259 179 */ 180 void __init i8259_init(unsigned long intack_addr, int offset) 181 { 182 unsigned long flags; 183 int i; 184 185 spin_lock_irqsave(&i8259_lock, flags); 186 i8259_pic_irq_offset = offset; 187 188 /* init master interrupt controller */ 189 outb(0x11, 0x20); /* Start init sequence */ 190 outb(0x00, 0x21); /* Vector base */ 191 outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ 192 outb(0x01, 0x21); /* Select 8086 mode */ 193 194 /* init slave interrupt controller */ 195 outb(0x11, 0xA0); /* Start init sequence */ 196 outb(0x08, 0xA1); /* Vector base */ 197 outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ 198 outb(0x01, 0xA1); /* Select 8086 mode */ 199 200 /* always read ISR */ 201 outb(0x0B, 0x20); 202 outb(0x0B, 0xA0); 203 204 /* Mask all interrupts */ 205 outb(cached_A1, 0xA1); 206 outb(cached_21, 0x21); 207 208 spin_unlock_irqrestore(&i8259_lock, flags); 209 210 for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) 211 irq_desc[offset + i].handler = &i8259_pic; 212 213 /* reserve our resources */ 214 setup_irq(offset + 2, &i8259_irqaction); 215 request_resource(&ioport_resource, &pic1_iores); 216 request_resource(&ioport_resource, &pic2_iores); 217 request_resource(&ioport_resource, &pic_edgectrl_iores); 218 219 if (intack_addr != 0) 220 pci_intack = ioremap(intack_addr, 1); 221 222 } 223