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(struct irq_data *d)
  37{
  38        spin_lock(&i8259_irq_lock);
  39        i8259_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->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(struct irq_data *d)
  51{
  52        spin_lock(&i8259_irq_lock);
  53        __i8259a_disable_irq(d->irq);
  54        spin_unlock(&i8259_irq_lock);
  55}
  56
  57void
  58i8259a_mask_and_ack_irq(struct irq_data *d)
  59{
  60        unsigned int irq = d->irq;
  61
  62        spin_lock(&i8259_irq_lock);
  63        __i8259a_disable_irq(irq);
  64
  65        /* Ack the interrupt making it the lowest priority.  */
  66        if (irq >= 8) {
  67                outb(0xE0 | (irq - 8), 0xa0);   /* ack the slave */
  68                irq = 2;
  69        }
  70        outb(0xE0 | irq, 0x20);                 /* ack the master */
  71        spin_unlock(&i8259_irq_lock);
  72}
  73
  74struct irq_chip i8259a_irq_type = {
  75        .name           = "XT-PIC",
  76        .irq_unmask     = i8259a_enable_irq,
  77        .irq_mask       = i8259a_disable_irq,
  78        .irq_mask_ack   = i8259a_mask_and_ack_irq,
  79};
  80
  81void __init
  82init_i8259a_irqs(void)
  83{
  84        static struct irqaction cascade = {
  85                .handler        = no_action,
  86                .name           = "cascade",
  87        };
  88
  89        long i;
  90
  91        outb(0xff, 0x21);       /* mask all of 8259A-1 */
  92        outb(0xff, 0xA1);       /* mask all of 8259A-2 */
  93
  94        for (i = 0; i < 16; i++) {
  95                irq_set_chip_and_handler(i, &i8259a_irq_type, handle_level_irq);
  96        }
  97
  98        setup_irq(2, &cascade);
  99}
 100
 101
 102#if defined(CONFIG_ALPHA_GENERIC)
 103# define IACK_SC        alpha_mv.iack_sc
 104#elif defined(CONFIG_ALPHA_APECS)
 105# define IACK_SC        APECS_IACK_SC
 106#elif defined(CONFIG_ALPHA_LCA)
 107# define IACK_SC        LCA_IACK_SC
 108#elif defined(CONFIG_ALPHA_CIA)
 109# define IACK_SC        CIA_IACK_SC
 110#elif defined(CONFIG_ALPHA_PYXIS)
 111# define IACK_SC        PYXIS_IACK_SC
 112#elif defined(CONFIG_ALPHA_TITAN)
 113# define IACK_SC        TITAN_IACK_SC
 114#elif defined(CONFIG_ALPHA_TSUNAMI)
 115# define IACK_SC        TSUNAMI_IACK_SC
 116#elif defined(CONFIG_ALPHA_IRONGATE)
 117# define IACK_SC        IRONGATE_IACK_SC
 118#endif
 119/* Note that CONFIG_ALPHA_POLARIS is intentionally left out here, since
 120   sys_rx164 wants to use isa_no_iack_sc_device_interrupt for some reason.  */
 121
 122#if defined(IACK_SC)
 123void
 124isa_device_interrupt(unsigned long vector)
 125{
 126        /*
 127         * Generate a PCI interrupt acknowledge cycle.  The PIC will
 128         * respond with the interrupt vector of the highest priority
 129         * interrupt that is pending.  The PALcode sets up the
 130         * interrupts vectors such that irq level L generates vector L.
 131         */
 132        int j = *(vuip) IACK_SC;
 133        j &= 0xff;
 134        handle_irq(j);
 135}
 136#endif
 137
 138#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
 139void
 140isa_no_iack_sc_device_interrupt(unsigned long vector)
 141{
 142        unsigned long pic;
 143
 144        /*
 145         * It seems to me that the probability of two or more *device*
 146         * interrupts occurring at almost exactly the same time is
 147         * pretty low.  So why pay the price of checking for
 148         * additional interrupts here if the common case can be
 149         * handled so much easier?
 150         */
 151        /* 
 152         *  The first read of gives you *all* interrupting lines.
 153         *  Therefore, read the mask register and and out those lines
 154         *  not enabled.  Note that some documentation has 21 and a1 
 155         *  write only.  This is not true.
 156         */
 157        pic = inb(0x20) | (inb(0xA0) << 8);     /* read isr */
 158        pic &= 0xFFFB;                          /* mask out cascade & hibits */
 159
 160        while (pic) {
 161                int j = ffz(~pic);
 162                pic &= pic - 1;
 163                handle_irq(j);
 164        }
 165}
 166#endif
 167