linux/arch/mips/sgi-ip32/ip32-irq.c
<<
>>
Prefs
   1/*
   2 * Code to handle IP32 IRQs
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * Copyright (C) 2000 Harald Koerfgen
   9 * Copyright (C) 2001 Keith M Wesolowski
  10 */
  11#include <linux/init.h>
  12#include <linux/kernel_stat.h>
  13#include <linux/types.h>
  14#include <linux/interrupt.h>
  15#include <linux/irq.h>
  16#include <linux/bitops.h>
  17#include <linux/kernel.h>
  18#include <linux/mm.h>
  19#include <linux/random.h>
  20#include <linux/sched.h>
  21
  22#include <asm/irq_cpu.h>
  23#include <asm/mipsregs.h>
  24#include <asm/signal.h>
  25#include <asm/system.h>
  26#include <asm/time.h>
  27#include <asm/ip32/crime.h>
  28#include <asm/ip32/mace.h>
  29#include <asm/ip32/ip32_ints.h>
  30
  31/* issue a PIO read to make sure no PIO writes are pending */
  32static void inline flush_crime_bus(void)
  33{
  34        crime->control;
  35}
  36
  37static void inline flush_mace_bus(void)
  38{
  39        mace->perif.ctrl.misc;
  40}
  41
  42/*
  43 * O2 irq map
  44 *
  45 * IP0 -> software (ignored)
  46 * IP1 -> software (ignored)
  47 * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ???
  48 * IP3 -> (irq1) X unknown
  49 * IP4 -> (irq2) X unknown
  50 * IP5 -> (irq3) X unknown
  51 * IP6 -> (irq4) X unknown
  52 * IP7 -> (irq5) 7 CPU count/compare timer (system timer)
  53 *
  54 * crime: (C)
  55 *
  56 * CRIME_INT_STAT 31:0:
  57 *
  58 * 0  ->  8  Video in 1
  59 * 1  ->  9 Video in 2
  60 * 2  -> 10  Video out
  61 * 3  -> 11  Mace ethernet
  62 * 4  -> S  SuperIO sub-interrupt
  63 * 5  -> M  Miscellaneous sub-interrupt
  64 * 6  -> A  Audio sub-interrupt
  65 * 7  -> 15  PCI bridge errors
  66 * 8  -> 16  PCI SCSI aic7xxx 0
  67 * 9  -> 17 PCI SCSI aic7xxx 1
  68 * 10 -> 18 PCI slot 0
  69 * 11 -> 19 unused (PCI slot 1)
  70 * 12 -> 20 unused (PCI slot 2)
  71 * 13 -> 21 unused (PCI shared 0)
  72 * 14 -> 22 unused (PCI shared 1)
  73 * 15 -> 23 unused (PCI shared 2)
  74 * 16 -> 24 GBE0 (E)
  75 * 17 -> 25 GBE1 (E)
  76 * 18 -> 26 GBE2 (E)
  77 * 19 -> 27 GBE3 (E)
  78 * 20 -> 28 CPU errors
  79 * 21 -> 29 Memory errors
  80 * 22 -> 30 RE empty edge (E)
  81 * 23 -> 31 RE full edge (E)
  82 * 24 -> 32 RE idle edge (E)
  83 * 25 -> 33 RE empty level
  84 * 26 -> 34 RE full level
  85 * 27 -> 35 RE idle level
  86 * 28 -> 36 unused (software 0) (E)
  87 * 29 -> 37 unused (software 1) (E)
  88 * 30 -> 38 unused (software 2) - crime 1.5 CPU SysCorError (E)
  89 * 31 -> 39 VICE
  90 *
  91 * S, M, A: Use the MACE ISA interrupt register
  92 * MACE_ISA_INT_STAT 31:0
  93 *
  94 * 0-7 -> 40-47 Audio
  95 * 8 -> 48 RTC
  96 * 9 -> 49 Keyboard
  97 * 10 -> X Keyboard polled
  98 * 11 -> 51 Mouse
  99 * 12 -> X Mouse polled
 100 * 13-15 -> 53-55 Count/compare timers
 101 * 16-19 -> 56-59 Parallel (16 E)
 102 * 20-25 -> 60-62 Serial 1 (22 E)
 103 * 26-31 -> 66-71 Serial 2 (28 E)
 104 *
 105 * Note that this means IRQs 12-14, 50, and 52 do not exist.  This is a
 106 * different IRQ map than IRIX uses, but that's OK as Linux irq handling
 107 * is quite different anyway.
 108 */
 109
 110/* Some initial interrupts to set up */
 111extern irqreturn_t crime_memerr_intr(int irq, void *dev_id);
 112extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
 113
 114static struct irqaction memerr_irq = {
 115        .handler = crime_memerr_intr,
 116        .flags = IRQF_DISABLED,
 117        .name = "CRIME memory error",
 118};
 119
 120static struct irqaction cpuerr_irq = {
 121        .handler = crime_cpuerr_intr,
 122        .flags = IRQF_DISABLED,
 123        .name = "CRIME CPU error",
 124};
 125
 126/*
 127 * This is for pure CRIME interrupts - ie not MACE.  The advantage?
 128 * We get to split the register in half and do faster lookups.
 129 */
 130
 131static uint64_t crime_mask;
 132
 133static inline void crime_enable_irq(struct irq_data *d)
 134{
 135        unsigned int bit = d->irq - CRIME_IRQ_BASE;
 136
 137        crime_mask |= 1 << bit;
 138        crime->imask = crime_mask;
 139}
 140
 141static inline void crime_disable_irq(struct irq_data *d)
 142{
 143        unsigned int bit = d->irq - CRIME_IRQ_BASE;
 144
 145        crime_mask &= ~(1 << bit);
 146        crime->imask = crime_mask;
 147        flush_crime_bus();
 148}
 149
 150static struct irq_chip crime_level_interrupt = {
 151        .name           = "IP32 CRIME",
 152        .irq_mask       = crime_disable_irq,
 153        .irq_unmask     = crime_enable_irq,
 154};
 155
 156static void crime_edge_mask_and_ack_irq(struct irq_data *d)
 157{
 158        unsigned int bit = d->irq - CRIME_IRQ_BASE;
 159        uint64_t crime_int;
 160
 161        /* Edge triggered interrupts must be cleared. */
 162        crime_int = crime->hard_int;
 163        crime_int &= ~(1 << bit);
 164        crime->hard_int = crime_int;
 165
 166        crime_disable_irq(d);
 167}
 168
 169static struct irq_chip crime_edge_interrupt = {
 170        .name           = "IP32 CRIME",
 171        .irq_ack        = crime_edge_mask_and_ack_irq,
 172        .irq_mask       = crime_disable_irq,
 173        .irq_mask_ack   = crime_edge_mask_and_ack_irq,
 174        .irq_unmask     = crime_enable_irq,
 175};
 176
 177/*
 178 * This is for MACE PCI interrupts.  We can decrease bus traffic by masking
 179 * as close to the source as possible.  This also means we can take the
 180 * next chunk of the CRIME register in one piece.
 181 */
 182
 183static unsigned long macepci_mask;
 184
 185static void enable_macepci_irq(struct irq_data *d)
 186{
 187        macepci_mask |= MACEPCI_CONTROL_INT(d->irq - MACEPCI_SCSI0_IRQ);
 188        mace->pci.control = macepci_mask;
 189        crime_mask |= 1 << (d->irq - CRIME_IRQ_BASE);
 190        crime->imask = crime_mask;
 191}
 192
 193static void disable_macepci_irq(struct irq_data *d)
 194{
 195        crime_mask &= ~(1 << (d->irq - CRIME_IRQ_BASE));
 196        crime->imask = crime_mask;
 197        flush_crime_bus();
 198        macepci_mask &= ~MACEPCI_CONTROL_INT(d->irq - MACEPCI_SCSI0_IRQ);
 199        mace->pci.control = macepci_mask;
 200        flush_mace_bus();
 201}
 202
 203static struct irq_chip ip32_macepci_interrupt = {
 204        .name = "IP32 MACE PCI",
 205        .irq_mask = disable_macepci_irq,
 206        .irq_unmask = enable_macepci_irq,
 207};
 208
 209/* This is used for MACE ISA interrupts.  That means bits 4-6 in the
 210 * CRIME register.
 211 */
 212
 213#define MACEISA_AUDIO_INT       (MACEISA_AUDIO_SW_INT |         \
 214                                 MACEISA_AUDIO_SC_INT |         \
 215                                 MACEISA_AUDIO1_DMAT_INT |      \
 216                                 MACEISA_AUDIO1_OF_INT |        \
 217                                 MACEISA_AUDIO2_DMAT_INT |      \
 218                                 MACEISA_AUDIO2_MERR_INT |      \
 219                                 MACEISA_AUDIO3_DMAT_INT |      \
 220                                 MACEISA_AUDIO3_MERR_INT)
 221#define MACEISA_MISC_INT        (MACEISA_RTC_INT |              \
 222                                 MACEISA_KEYB_INT |             \
 223                                 MACEISA_KEYB_POLL_INT |        \
 224                                 MACEISA_MOUSE_INT |            \
 225                                 MACEISA_MOUSE_POLL_INT |       \
 226                                 MACEISA_TIMER0_INT |           \
 227                                 MACEISA_TIMER1_INT |           \
 228                                 MACEISA_TIMER2_INT)
 229#define MACEISA_SUPERIO_INT     (MACEISA_PARALLEL_INT |         \
 230                                 MACEISA_PAR_CTXA_INT |         \
 231                                 MACEISA_PAR_CTXB_INT |         \
 232                                 MACEISA_PAR_MERR_INT |         \
 233                                 MACEISA_SERIAL1_INT |          \
 234                                 MACEISA_SERIAL1_TDMAT_INT |    \
 235                                 MACEISA_SERIAL1_TDMAPR_INT |   \
 236                                 MACEISA_SERIAL1_TDMAME_INT |   \
 237                                 MACEISA_SERIAL1_RDMAT_INT |    \
 238                                 MACEISA_SERIAL1_RDMAOR_INT |   \
 239                                 MACEISA_SERIAL2_INT |          \
 240                                 MACEISA_SERIAL2_TDMAT_INT |    \
 241                                 MACEISA_SERIAL2_TDMAPR_INT |   \
 242                                 MACEISA_SERIAL2_TDMAME_INT |   \
 243                                 MACEISA_SERIAL2_RDMAT_INT |    \
 244                                 MACEISA_SERIAL2_RDMAOR_INT)
 245
 246static unsigned long maceisa_mask;
 247
 248static void enable_maceisa_irq(struct irq_data *d)
 249{
 250        unsigned int crime_int = 0;
 251
 252        pr_debug("maceisa enable: %u\n", d->irq);
 253
 254        switch (d->irq) {
 255        case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ:
 256                crime_int = MACE_AUDIO_INT;
 257                break;
 258        case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ:
 259                crime_int = MACE_MISC_INT;
 260                break;
 261        case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ:
 262                crime_int = MACE_SUPERIO_INT;
 263                break;
 264        }
 265        pr_debug("crime_int %08x enabled\n", crime_int);
 266        crime_mask |= crime_int;
 267        crime->imask = crime_mask;
 268        maceisa_mask |= 1 << (d->irq - MACEISA_AUDIO_SW_IRQ);
 269        mace->perif.ctrl.imask = maceisa_mask;
 270}
 271
 272static void disable_maceisa_irq(struct irq_data *d)
 273{
 274        unsigned int crime_int = 0;
 275
 276        maceisa_mask &= ~(1 << (d->irq - MACEISA_AUDIO_SW_IRQ));
 277        if (!(maceisa_mask & MACEISA_AUDIO_INT))
 278                crime_int |= MACE_AUDIO_INT;
 279        if (!(maceisa_mask & MACEISA_MISC_INT))
 280                crime_int |= MACE_MISC_INT;
 281        if (!(maceisa_mask & MACEISA_SUPERIO_INT))
 282                crime_int |= MACE_SUPERIO_INT;
 283        crime_mask &= ~crime_int;
 284        crime->imask = crime_mask;
 285        flush_crime_bus();
 286        mace->perif.ctrl.imask = maceisa_mask;
 287        flush_mace_bus();
 288}
 289
 290static void mask_and_ack_maceisa_irq(struct irq_data *d)
 291{
 292        unsigned long mace_int;
 293
 294        /* edge triggered */
 295        mace_int = mace->perif.ctrl.istat;
 296        mace_int &= ~(1 << (d->irq - MACEISA_AUDIO_SW_IRQ));
 297        mace->perif.ctrl.istat = mace_int;
 298
 299        disable_maceisa_irq(d);
 300}
 301
 302static struct irq_chip ip32_maceisa_level_interrupt = {
 303        .name           = "IP32 MACE ISA",
 304        .irq_mask       = disable_maceisa_irq,
 305        .irq_unmask     = enable_maceisa_irq,
 306};
 307
 308static struct irq_chip ip32_maceisa_edge_interrupt = {
 309        .name           = "IP32 MACE ISA",
 310        .irq_ack        = mask_and_ack_maceisa_irq,
 311        .irq_mask       = disable_maceisa_irq,
 312        .irq_mask_ack   = mask_and_ack_maceisa_irq,
 313        .irq_unmask     = enable_maceisa_irq,
 314};
 315
 316/* This is used for regular non-ISA, non-PCI MACE interrupts.  That means
 317 * bits 0-3 and 7 in the CRIME register.
 318 */
 319
 320static void enable_mace_irq(struct irq_data *d)
 321{
 322        unsigned int bit = d->irq - CRIME_IRQ_BASE;
 323
 324        crime_mask |= (1 << bit);
 325        crime->imask = crime_mask;
 326}
 327
 328static void disable_mace_irq(struct irq_data *d)
 329{
 330        unsigned int bit = d->irq - CRIME_IRQ_BASE;
 331
 332        crime_mask &= ~(1 << bit);
 333        crime->imask = crime_mask;
 334        flush_crime_bus();
 335}
 336
 337static struct irq_chip ip32_mace_interrupt = {
 338        .name = "IP32 MACE",
 339        .irq_mask = disable_mace_irq,
 340        .irq_unmask = enable_mace_irq,
 341};
 342
 343static void ip32_unknown_interrupt(void)
 344{
 345        printk("Unknown interrupt occurred!\n");
 346        printk("cp0_status: %08x\n", read_c0_status());
 347        printk("cp0_cause: %08x\n", read_c0_cause());
 348        printk("CRIME intr mask: %016lx\n", crime->imask);
 349        printk("CRIME intr status: %016lx\n", crime->istat);
 350        printk("CRIME hardware intr register: %016lx\n", crime->hard_int);
 351        printk("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask);
 352        printk("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat);
 353        printk("MACE PCI control register: %08x\n", mace->pci.control);
 354
 355        printk("Register dump:\n");
 356        show_regs(get_irq_regs());
 357
 358        printk("Please mail this report to linux-mips@linux-mips.org\n");
 359        printk("Spinning...");
 360        while(1) ;
 361}
 362
 363/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
 364/* change this to loop over all edge-triggered irqs, exception masked out ones */
 365static void ip32_irq0(void)
 366{
 367        uint64_t crime_int;
 368        int irq = 0;
 369
 370        /*
 371         * Sanity check interrupt numbering enum.
 372         * MACE got 32 interrupts and there are 32 MACE ISA interrupts daisy
 373         * chained.
 374         */
 375        BUILD_BUG_ON(CRIME_VICE_IRQ - MACE_VID_IN1_IRQ != 31);
 376        BUILD_BUG_ON(MACEISA_SERIAL2_RDMAOR_IRQ - MACEISA_AUDIO_SW_IRQ != 31);
 377
 378        crime_int = crime->istat & crime_mask;
 379
 380        /* crime sometime delivers spurious interrupts, ignore them */
 381        if (unlikely(crime_int == 0))
 382                return;
 383
 384        irq = MACE_VID_IN1_IRQ + __ffs(crime_int);
 385
 386        if (crime_int & CRIME_MACEISA_INT_MASK) {
 387                unsigned long mace_int = mace->perif.ctrl.istat;
 388                irq = __ffs(mace_int & maceisa_mask) + MACEISA_AUDIO_SW_IRQ;
 389        }
 390
 391        pr_debug("*irq %u*\n", irq);
 392        do_IRQ(irq);
 393}
 394
 395static void ip32_irq1(void)
 396{
 397        ip32_unknown_interrupt();
 398}
 399
 400static void ip32_irq2(void)
 401{
 402        ip32_unknown_interrupt();
 403}
 404
 405static void ip32_irq3(void)
 406{
 407        ip32_unknown_interrupt();
 408}
 409
 410static void ip32_irq4(void)
 411{
 412        ip32_unknown_interrupt();
 413}
 414
 415static void ip32_irq5(void)
 416{
 417        do_IRQ(MIPS_CPU_IRQ_BASE + 7);
 418}
 419
 420asmlinkage void plat_irq_dispatch(void)
 421{
 422        unsigned int pending = read_c0_status() & read_c0_cause();
 423
 424        if (likely(pending & IE_IRQ0))
 425                ip32_irq0();
 426        else if (unlikely(pending & IE_IRQ1))
 427                ip32_irq1();
 428        else if (unlikely(pending & IE_IRQ2))
 429                ip32_irq2();
 430        else if (unlikely(pending & IE_IRQ3))
 431                ip32_irq3();
 432        else if (unlikely(pending & IE_IRQ4))
 433                ip32_irq4();
 434        else if (likely(pending & IE_IRQ5))
 435                ip32_irq5();
 436}
 437
 438void __init arch_init_irq(void)
 439{
 440        unsigned int irq;
 441
 442        /* Install our interrupt handler, then clear and disable all
 443         * CRIME and MACE interrupts. */
 444        crime->imask = 0;
 445        crime->hard_int = 0;
 446        crime->soft_int = 0;
 447        mace->perif.ctrl.istat = 0;
 448        mace->perif.ctrl.imask = 0;
 449
 450        mips_cpu_irq_init();
 451        for (irq = CRIME_IRQ_BASE; irq <= IP32_IRQ_MAX; irq++) {
 452                switch (irq) {
 453                case MACE_VID_IN1_IRQ ... MACE_PCI_BRIDGE_IRQ:
 454                        irq_set_chip_and_handler_name(irq,
 455                                                      &ip32_mace_interrupt,
 456                                                      handle_level_irq,
 457                                                      "level");
 458                        break;
 459
 460                case MACEPCI_SCSI0_IRQ ...  MACEPCI_SHARED2_IRQ:
 461                        irq_set_chip_and_handler_name(irq,
 462                                                      &ip32_macepci_interrupt,
 463                                                      handle_level_irq,
 464                                                      "level");
 465                        break;
 466
 467                case CRIME_CPUERR_IRQ:
 468                case CRIME_MEMERR_IRQ:
 469                        irq_set_chip_and_handler_name(irq,
 470                                                      &crime_level_interrupt,
 471                                                      handle_level_irq,
 472                                                      "level");
 473                        break;
 474
 475                case CRIME_GBE0_IRQ ... CRIME_GBE3_IRQ:
 476                case CRIME_RE_EMPTY_E_IRQ ... CRIME_RE_IDLE_E_IRQ:
 477                case CRIME_SOFT0_IRQ ... CRIME_SOFT2_IRQ:
 478                case CRIME_VICE_IRQ:
 479                        irq_set_chip_and_handler_name(irq,
 480                                                      &crime_edge_interrupt,
 481                                                      handle_edge_irq,
 482                                                      "edge");
 483                        break;
 484
 485                case MACEISA_PARALLEL_IRQ:
 486                case MACEISA_SERIAL1_TDMAPR_IRQ:
 487                case MACEISA_SERIAL2_TDMAPR_IRQ:
 488                        irq_set_chip_and_handler_name(irq,
 489                                                      &ip32_maceisa_edge_interrupt,
 490                                                      handle_edge_irq,
 491                                                      "edge");
 492                        break;
 493
 494                default:
 495                        irq_set_chip_and_handler_name(irq,
 496                                                      &ip32_maceisa_level_interrupt,
 497                                                      handle_level_irq,
 498                                                      "level");
 499                        break;
 500                }
 501        }
 502        setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
 503        setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
 504
 505#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
 506        change_c0_status(ST0_IM, ALLINTS);
 507}
 508