linux/arch/alpha/kernel/irq_i8259.c
<<
>>
Prefs
   1/*
   2 *      linux/arch/alpha/kernel/irq_i8259.c
   3 *
   4 * This is the 'legacy' 8259A Programmable Interrupt Controller,
   5 * present in the majority of PC/AT boxes.
   6 *
   7 * Started hacking from linux-2.3.30pre6/arch/i386/kernel/i8259.c.
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/cache.h>
  12#include <linux/sched.h>
  13#include <linux/irq.h>
  14#include <linux/interrupt.h>
  15
  16#include <asm/io.h>
  17
  18#include "proto.h"
  19#include "irq_impl.h"
  20
  21
  22/* Note mask bit is true for DISABLED irqs.  */
  23static unsigned int cached_irq_mask = 0xffff;
  24static DEFINE_SPINLOCK(i8259_irq_lock);
  25
  26static inline void
  27i8259_update_irq_hw(unsigned int irq, unsigned long mask)
  28{
  29        int port = 0x21;
  30        if (irq & 8) mask >>= 8;
  31        if (irq & 8) port = 0xA1;
  32        outb(mask, port);
  33}
  34
  35inline void
  36i8259a_enable_irq(unsigned int irq)
  37{
  38        spin_lock(&i8259_irq_lock);
  39        i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
  40        spin_unlock(&i8259_irq_lock);
  41}
  42
  43static inline void
  44__i8259a_disable_irq(unsigned int irq)
  45{
  46        i8259_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
  47}
  48
  49void
  50i8259a_disable_irq(unsigned int irq)
  51{
  52        spin_lock(&i8259_irq_lock);
  53        __i8259a_disable_irq(irq);
  54        spin_unlock(&i8259_irq_lock);
  55}
  56
  57void
  58i8259a_mask_and_ack_irq(unsigned int irq)
  59{
  60        spin_lock(&i8259_irq_lock);
  61        __i8259a_disable_irq(irq);
  62
  63        /* Ack the interrupt making it the lowest priority.  */
  64        if (irq >= 8) {
  65                outb(0xE0 | (irq - 8), 0xa0);   /* ack the slave */
  66                irq = 2;
  67        }
  68        outb(0xE0 | irq, 0x20);                 /* ack the master */
  69        spin_unlock(&i8259_irq_lock);
  70}
  71
  72unsigned int
  73i8259a_startup_irq(unsigned int irq)
  74{
  75        i8259a_enable_irq(irq);
  76        return 0; /* never anything pending */
  77}
  78
  79void
  80i8259a_end_irq(unsigned int irq)
  81{
  82        if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  83                i8259a_enable_irq(irq);
  84}
  85
  86struct irq_chip i8259a_irq_type = {
  87        .name           = "XT-PIC",
  88        .startup        = i8259a_startup_irq,
  89        .shutdown       = i8259a_disable_irq,
  90        .enable         = i8259a_enable_irq,
  91        .disable        = i8259a_disable_irq,
  92        .ack            = i8259a_mask_and_ack_irq,
  93        .end            = i8259a_end_irq,
  94};
  95
  96void __init
  97init_i8259a_irqs(void)
  98{
  99        static struct irqaction cascade = {
 100                .handler        = no_action,
 101                .name           = "cascade",
 102        };
 103
 104        long i;
 105
 106        outb(0xff, 0x21);       /* mask all of 8259A-1 */
 107        outb(0xff, 0xA1);       /* mask all of 8259A-2 */
 108
 109        for (i = 0; i < 16; i++) {
 110                irq_desc[i].status = IRQ_DISABLED;
 111                irq_desc[i].chip = &i8259a_irq_type;
 112        }
 113
 114        setup_irq(2, &cascade);
 115}
 116
 117
 118#if defined(CONFIG_ALPHA_GENERIC)
 119# define IACK_SC        alpha_mv.iack_sc
 120#elif defined(CONFIG_ALPHA_APECS)
 121# define IACK_SC        APECS_IACK_SC
 122#elif defined(CONFIG_ALPHA_LCA)
 123# define IACK_SC        LCA_IACK_SC
 124#elif defined(CONFIG_ALPHA_CIA)
 125# define IACK_SC        CIA_IACK_SC
 126#elif defined(CONFIG_ALPHA_PYXIS)
 127# define IACK_SC        PYXIS_IACK_SC
 128#elif defined(CONFIG_ALPHA_TITAN)
 129# define IACK_SC        TITAN_IACK_SC
 130#elif defined(CONFIG_ALPHA_TSUNAMI)
 131# define IACK_SC        TSUNAMI_IACK_SC
 132#elif defined(CONFIG_ALPHA_IRONGATE)
 133# define IACK_SC        IRONGATE_IACK_SC
 134#endif
 135/* Note that CONFIG_ALPHA_POLARIS is intentionally left out here, since
 136   sys_rx164 wants to use isa_no_iack_sc_device_interrupt for some reason.  */
 137
 138#if defined(IACK_SC)
 139void
 140isa_device_interrupt(unsigned long vector)
 141{
 142        /*
 143         * Generate a PCI interrupt acknowledge cycle.  The PIC will
 144         * respond with the interrupt vector of the highest priority
 145         * interrupt that is pending.  The PALcode sets up the
 146         * interrupts vectors such that irq level L generates vector L.
 147         */
 148        int j = *(vuip) IACK_SC;
 149        j &= 0xff;
 150        handle_irq(j);
 151}
 152#endif
 153
 154#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
 155void
 156isa_no_iack_sc_device_interrupt(unsigned long vector)
 157{
 158        unsigned long pic;
 159
 160        /*
 161         * It seems to me that the probability of two or more *device*
 162         * interrupts occurring at almost exactly the same time is
 163         * pretty low.  So why pay the price of checking for
 164         * additional interrupts here if the common case can be
 165         * handled so much easier?
 166         */
 167        /* 
 168         *  The first read of gives you *all* interrupting lines.
 169         *  Therefore, read the mask register and and out those lines
 170         *  not enabled.  Note that some documentation has 21 and a1 
 171         *  write only.  This is not true.
 172         */
 173        pic = inb(0x20) | (inb(0xA0) << 8);     /* read isr */
 174        pic &= 0xFFFB;                          /* mask out cascade & hibits */
 175
 176        while (pic) {
 177                int j = ffz(~pic);
 178                pic &= pic - 1;
 179                handle_irq(j);
 180        }
 181}
 182#endif
 183
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.