^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Code to handle x86 style IRQs plus some generic interrupt stuff.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 1992 Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 1994 - 2000 Ralf Baechle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/syscore_ops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/i8259.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * This is the 'legacy' 8259A Programmable Interrupt Controller,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * present in the majority of PC/AT boxes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * plus some generic x86 specific things if generic specifics makes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * any sense at all.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * this file should become arch/i386/kernel/irq.c when the old irq.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * moves to arch independent land
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static int i8259A_auto_eoi = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) DEFINE_RAW_SPINLOCK(i8259A_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void disable_8259A_irq(struct irq_data *d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static void enable_8259A_irq(struct irq_data *d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static void mask_and_ack_8259A(struct irq_data *d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static void init_8259A(int auto_eoi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int (*i8259_poll)(void) = i8259_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static struct irq_chip i8259A_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .name = "XT-PIC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .irq_mask = disable_8259A_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) .irq_disable = disable_8259A_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .irq_unmask = enable_8259A_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .irq_mask_ack = mask_and_ack_8259A,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * 8259A PIC functions to handle ISA devices:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) void i8259_set_poll(int (*poll)(void))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) i8259_poll = poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * This contains the irq mask for both 8259A irq controllers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static unsigned int cached_irq_mask = 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define cached_master_mask (cached_irq_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define cached_slave_mask (cached_irq_mask >> 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static void disable_8259A_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned int mask, irq = d->irq - I8259A_IRQ_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mask = 1 << irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) raw_spin_lock_irqsave(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) cached_irq_mask |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (irq & 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) outb(cached_slave_mask, PIC_SLAVE_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) outb(cached_master_mask, PIC_MASTER_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) raw_spin_unlock_irqrestore(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static void enable_8259A_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) unsigned int mask, irq = d->irq - I8259A_IRQ_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) mask = ~(1 << irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) raw_spin_lock_irqsave(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) cached_irq_mask &= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (irq & 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) outb(cached_slave_mask, PIC_SLAVE_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) outb(cached_master_mask, PIC_MASTER_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) raw_spin_unlock_irqrestore(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) void make_8259A_irq(unsigned int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) disable_irq_nosync(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) enable_irq(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * This function assumes to be called rarely. Switching between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * 8259A registers is slow.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * This has to be protected by the irq controller spinlock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * before being called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static inline int i8259A_irq_real(unsigned int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int irqmask = 1 << irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (irq < 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) outb(0x0B, PIC_MASTER_CMD); /* ISR register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) value = inb(PIC_MASTER_CMD) & irqmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) outb(0x0B, PIC_SLAVE_CMD); /* ISR register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Careful! The 8259A is a fragile beast, it pretty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * much _has_ to be done exactly like this (mask it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * first, _then_ send the EOI, and the order of EOI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * to the two 8259s is important!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static void mask_and_ack_8259A(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) irqmask = 1 << irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) raw_spin_lock_irqsave(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * Lightweight spurious IRQ detection. We do not want
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * to overdo spurious IRQ handling - it's usually a sign
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * of hardware problems, so we only do the checks we can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * do without slowing down good hardware unnecessarily.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * Note that IRQ7 and IRQ15 (the two spurious IRQs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * usually resulting from the 8259A-1|2 PICs) occur
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * even if the IRQ is masked in the 8259A. Thus we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * can check spurious 8259A IRQs without doing the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * quite slow i8259A_irq_real() call for every IRQ.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * This does not cover 100% of spurious interrupts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * but should be enough to warn the user that there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * is something bad going on ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (cached_irq_mask & irqmask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) goto spurious_8259A_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) cached_irq_mask |= irqmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) handle_real_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (irq & 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) outb(cached_slave_mask, PIC_SLAVE_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) outb(cached_master_mask, PIC_MASTER_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) raw_spin_unlock_irqrestore(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) spurious_8259A_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * this is the slow path - should happen rarely.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (i8259A_irq_real(irq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * oops, the IRQ _is_ in service according to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * 8259A - not spurious, go handle it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) goto handle_real_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static int spurious_irq_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * At this point we can be sure the IRQ is spurious,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * lets ACK and report it. [once per IRQ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!(spurious_irq_mask & irqmask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) spurious_irq_mask |= irqmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) atomic_inc(&irq_err_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * Theoretically we do not have to handle this IRQ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * but in Linux this does not cause problems and is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * simpler for us.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) goto handle_real_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static void i8259A_resume(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (i8259A_auto_eoi >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) init_8259A(i8259A_auto_eoi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static void i8259A_shutdown(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* Put the i8259A into a quiescent state that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * the kernel initialization code can get it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * out of.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (i8259A_auto_eoi >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static struct syscore_ops i8259_syscore_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .resume = i8259A_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .shutdown = i8259A_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static void init_8259A(int auto_eoi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) i8259A_auto_eoi = auto_eoi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) raw_spin_lock_irqsave(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * outb_p - this has to work on a wide range of PC hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (auto_eoi) /* master does Auto EOI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) else /* master expects normal EOI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (auto_eoi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * In AEOI mode we just have to mask the interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * when acking.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) i8259A_chip.irq_mask_ack = disable_8259A_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) i8259A_chip.irq_mask_ack = mask_and_ack_8259A;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) udelay(100); /* wait for 8259A to initialize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) raw_spin_unlock_irqrestore(&i8259A_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static struct resource pic1_io_resource = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .name = "pic1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .start = PIC_MASTER_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .end = PIC_MASTER_IMR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .flags = IORESOURCE_IO | IORESOURCE_BUSY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) static struct resource pic2_io_resource = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .name = "pic2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) .start = PIC_SLAVE_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .end = PIC_SLAVE_IMR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .flags = IORESOURCE_IO | IORESOURCE_BUSY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) irq_hw_number_t hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) irq_set_probe(virq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static const struct irq_domain_ops i8259A_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .map = i8259A_irq_domain_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .xlate = irq_domain_xlate_onecell,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * On systems with i8259-style interrupt controllers we assume for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) * driver compatibility reasons interrupts 0 - 15 to be the i8259
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) * interrupts even if the hardware uses a different interrupt numbering.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) * PIC_CASCADE_IR is cascade interrupt to second interrupt controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) int irq = I8259A_IRQ_BASE + PIC_CASCADE_IR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) insert_resource(&ioport_resource, &pic1_io_resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) insert_resource(&ioport_resource, &pic2_io_resource);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) init_8259A(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) &i8259A_ops, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (!domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) panic("Failed to add i8259 IRQ domain");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) pr_err("Failed to register cascade interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) register_syscore_ops(&i8259_syscore_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) void __init init_i8259_irqs(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) __init_i8259_irqs(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static void i8259_irq_dispatch(struct irq_desc *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) struct irq_domain *domain = irq_desc_get_handler_data(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) int hwirq = i8259_poll();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) unsigned int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (hwirq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) irq = irq_linear_revmap(domain, hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) generic_handle_irq(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) int __init i8259_of_init(struct device_node *node, struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct irq_domain *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned int parent_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) domain = __init_i8259_irqs(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) parent_irq = irq_of_parse_and_map(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (!parent_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) pr_err("Failed to map i8259 parent IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) irq_domain_remove(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) irq_set_chained_handler_and_data(parent_irq, i8259_irq_dispatch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init);