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