linux/arch/m68k/mac/macints.c
<<
>>
Prefs
   1/*
   2 *      Macintosh interrupts
   3 *
   4 * General design:
   5 * In contrary to the Amiga and Atari platforms, the Mac hardware seems to
   6 * exclusively use the autovector interrupts (the 'generic level0-level7'
   7 * interrupts with exception vectors 0x19-0x1f). The following interrupt levels
   8 * are used:
   9 *      1       - VIA1
  10 *                - slot 0: one second interrupt (CA2)
  11 *                - slot 1: VBlank (CA1)
  12 *                - slot 2: ADB data ready (SR full)
  13 *                - slot 3: ADB data  (CB2)
  14 *                - slot 4: ADB clock (CB1)
  15 *                - slot 5: timer 2
  16 *                - slot 6: timer 1
  17 *                - slot 7: status of IRQ; signals 'any enabled int.'
  18 *
  19 *      2       - VIA2 or RBV
  20 *                - slot 0: SCSI DRQ (CA2)
  21 *                - slot 1: NUBUS IRQ (CA1) need to read port A to find which
  22 *                - slot 2: /EXP IRQ (only on IIci)
  23 *                - slot 3: SCSI IRQ (CB2)
  24 *                - slot 4: ASC IRQ (CB1)
  25 *                - slot 5: timer 2 (not on IIci)
  26 *                - slot 6: timer 1 (not on IIci)
  27 *                - slot 7: status of IRQ; signals 'any enabled int.'
  28 *
  29 * Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
  30 *
  31 *      3       - unused (?)
  32 *
  33 *      4       - SCC
  34 *
  35 *      5       - unused (?)
  36 *                [serial errors or special conditions seem to raise level 6
  37 *                interrupts on some models (LC4xx?)]
  38 *
  39 *      6       - off switch (?)
  40 *
  41 * Machines with Quadra-like VIA hardware, except PSC and PMU machines, support
  42 * an alternate interrupt mapping, as used by A/UX. It spreads ethernet and
  43 * sound out to their own autovector IRQs and gives VIA1 a higher priority:
  44 *
  45 *      1       - unused (?)
  46 *
  47 *      3       - on-board SONIC
  48 *
  49 *      5       - Apple Sound Chip (ASC)
  50 *
  51 *      6       - VIA1
  52 *
  53 * For OSS Macintoshes (IIfx only), we apply an interrupt mapping similar to
  54 * the Quadra (A/UX) mapping:
  55 *
  56 *      1       - ISM IOP (ADB)
  57 *
  58 *      2       - SCSI
  59 *
  60 *      3       - NuBus
  61 *
  62 *      4       - SCC IOP
  63 *
  64 *      6       - VIA1
  65 *
  66 * For PSC Macintoshes (660AV, 840AV):
  67 *
  68 *      3       - PSC level 3
  69 *                - slot 0: MACE
  70 *
  71 *      4       - PSC level 4
  72 *                - slot 1: SCC channel A interrupt
  73 *                - slot 2: SCC channel B interrupt
  74 *                - slot 3: MACE DMA
  75 *
  76 *      5       - PSC level 5
  77 *
  78 *      6       - PSC level 6
  79 *
  80 * Finally we have good 'ole level 7, the non-maskable interrupt:
  81 *
  82 *      7       - NMI (programmer's switch on the back of some Macs)
  83 *                Also RAM parity error on models which support it (IIc, IIfx?)
  84 *
  85 * The current interrupt logic looks something like this:
  86 *
  87 * - We install dispatchers for the autovector interrupts (1-7). These
  88 *   dispatchers are responsible for querying the hardware (the
  89 *   VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
  90 *   this information a machspec interrupt number is generated by placing the
  91 *   index of the interrupt hardware into the low three bits and the original
  92 *   autovector interrupt number in the upper 5 bits. The handlers for the
  93 *   resulting machspec interrupt are then called.
  94 *
  95 * - Nubus is a special case because its interrupts are hidden behind two
  96 *   layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
  97 *   which translates to IRQ number 17. In this spot we install _another_
  98 *   dispatcher. This dispatcher finds the interrupting slot number (9-F) and
  99 *   then forms a new machspec interrupt number as above with the slot number
 100 *   minus 9 in the low three bits and the pseudo-level 7 in the upper five
 101 *   bits.  The handlers for this new machspec interrupt number are then
 102 *   called. This puts Nubus interrupts into the range 56-62.
 103 *
 104 * - The Baboon interrupts (used on some PowerBooks) are an even more special
 105 *   case. They're hidden behind the Nubus slot $C interrupt thus adding a
 106 *   third layer of indirection. Why oh why did the Apple engineers do that?
 107 *
 108 */
 109
 110#include <linux/types.h>
 111#include <linux/kernel.h>
 112#include <linux/sched.h>
 113#include <linux/interrupt.h>
 114#include <linux/irq.h>
 115#include <linux/delay.h>
 116
 117#include <asm/irq.h>
 118#include <asm/macintosh.h>
 119#include <asm/macints.h>
 120#include <asm/mac_via.h>
 121#include <asm/mac_psc.h>
 122#include <asm/mac_oss.h>
 123#include <asm/mac_iop.h>
 124#include <asm/mac_baboon.h>
 125#include <asm/hwtest.h>
 126#include <asm/irq_regs.h>
 127
 128#define SHUTUP_SONIC
 129
 130/*
 131 * console_loglevel determines NMI handler function
 132 */
 133
 134irqreturn_t mac_nmi_handler(int, void *);
 135irqreturn_t mac_debug_handler(int, void *);
 136
 137/* #define DEBUG_MACINTS */
 138
 139static unsigned int mac_irq_startup(struct irq_data *);
 140static void mac_irq_shutdown(struct irq_data *);
 141
 142static struct irq_chip mac_irq_chip = {
 143        .name           = "mac",
 144        .irq_enable     = mac_irq_enable,
 145        .irq_disable    = mac_irq_disable,
 146        .irq_startup    = mac_irq_startup,
 147        .irq_shutdown   = mac_irq_shutdown,
 148};
 149
 150void __init mac_init_IRQ(void)
 151{
 152#ifdef DEBUG_MACINTS
 153        printk("mac_init_IRQ(): Setting things up...\n");
 154#endif
 155        m68k_setup_irq_controller(&mac_irq_chip, handle_simple_irq, IRQ_USER,
 156                                  NUM_MAC_SOURCES - IRQ_USER);
 157        /* Make sure the SONIC interrupt is cleared or things get ugly */
 158#ifdef SHUTUP_SONIC
 159        printk("Killing onboard sonic... ");
 160        /* This address should hopefully be mapped already */
 161        if (hwreg_present((void*)(0x50f0a000))) {
 162                *(long *)(0x50f0a014) = 0x7fffL;
 163                *(long *)(0x50f0a010) = 0L;
 164        }
 165        printk("Done.\n");
 166#endif /* SHUTUP_SONIC */
 167
 168        /*
 169         * Now register the handlers for the master IRQ handlers
 170         * at levels 1-7. Most of the work is done elsewhere.
 171         */
 172
 173        if (oss_present)
 174                oss_register_interrupts();
 175        else
 176                via_register_interrupts();
 177        if (psc_present)
 178                psc_register_interrupts();
 179        if (baboon_present)
 180                baboon_register_interrupts();
 181        iop_register_interrupts();
 182        if (request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",
 183                        mac_nmi_handler))
 184                pr_err("Couldn't register NMI\n");
 185#ifdef DEBUG_MACINTS
 186        printk("mac_init_IRQ(): Done!\n");
 187#endif
 188}
 189
 190/*
 191 *  mac_irq_enable - enable an interrupt source
 192 * mac_irq_disable - disable an interrupt source
 193 *
 194 * These routines are just dispatchers to the VIA/OSS/PSC routines.
 195 */
 196
 197void mac_irq_enable(struct irq_data *data)
 198{
 199        int irq = data->irq;
 200        int irq_src = IRQ_SRC(irq);
 201
 202        switch(irq_src) {
 203        case 1:
 204        case 2:
 205        case 7:
 206                if (oss_present)
 207                        oss_irq_enable(irq);
 208                else
 209                        via_irq_enable(irq);
 210                break;
 211        case 3:
 212        case 4:
 213        case 5:
 214        case 6:
 215                if (psc_present)
 216                        psc_irq_enable(irq);
 217                else if (oss_present)
 218                        oss_irq_enable(irq);
 219                break;
 220        case 8:
 221                if (baboon_present)
 222                        baboon_irq_enable(irq);
 223                break;
 224        }
 225}
 226
 227void mac_irq_disable(struct irq_data *data)
 228{
 229        int irq = data->irq;
 230        int irq_src = IRQ_SRC(irq);
 231
 232        switch(irq_src) {
 233        case 1:
 234        case 2:
 235        case 7:
 236                if (oss_present)
 237                        oss_irq_disable(irq);
 238                else
 239                        via_irq_disable(irq);
 240                break;
 241        case 3:
 242        case 4:
 243        case 5:
 244        case 6:
 245                if (psc_present)
 246                        psc_irq_disable(irq);
 247                else if (oss_present)
 248                        oss_irq_disable(irq);
 249                break;
 250        case 8:
 251                if (baboon_present)
 252                        baboon_irq_disable(irq);
 253                break;
 254        }
 255}
 256
 257static unsigned int mac_irq_startup(struct irq_data *data)
 258{
 259        int irq = data->irq;
 260
 261        if (IRQ_SRC(irq) == 7 && !oss_present)
 262                via_nubus_irq_startup(irq);
 263        else
 264                mac_irq_enable(data);
 265
 266        return 0;
 267}
 268
 269static void mac_irq_shutdown(struct irq_data *data)
 270{
 271        int irq = data->irq;
 272
 273        if (IRQ_SRC(irq) == 7 && !oss_present)
 274                via_nubus_irq_shutdown(irq);
 275        else
 276                mac_irq_disable(data);
 277}
 278
 279static int num_debug[8];
 280
 281irqreturn_t mac_debug_handler(int irq, void *dev_id)
 282{
 283        if (num_debug[irq] < 10) {
 284                printk("DEBUG: Unexpected IRQ %d\n", irq);
 285                num_debug[irq]++;
 286        }
 287        return IRQ_HANDLED;
 288}
 289
 290static int in_nmi;
 291static volatile int nmi_hold;
 292
 293irqreturn_t mac_nmi_handler(int irq, void *dev_id)
 294{
 295        int i;
 296        /*
 297         * generate debug output on NMI switch if 'debug' kernel option given
 298         * (only works with Penguin!)
 299         */
 300
 301        in_nmi++;
 302        for (i=0; i<100; i++)
 303                udelay(1000);
 304
 305        if (in_nmi == 1) {
 306                nmi_hold = 1;
 307                printk("... pausing, press NMI to resume ...");
 308        } else {
 309                printk(" ok!\n");
 310                nmi_hold = 0;
 311        }
 312
 313        barrier();
 314
 315        while (nmi_hold == 1)
 316                udelay(1000);
 317
 318        if (console_loglevel >= 8) {
 319#if 0
 320                struct pt_regs *fp = get_irq_regs();
 321                show_state();
 322                printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
 323                printk("d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
 324                       fp->d0, fp->d1, fp->d2, fp->d3);
 325                printk("d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
 326                       fp->d4, fp->d5, fp->a0, fp->a1);
 327
 328                if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
 329                        printk("Corrupted stack page\n");
 330                printk("Process %s (pid: %d, stackpage=%08lx)\n",
 331                        current->comm, current->pid, current->kernel_stack_page);
 332                if (intr_count == 1)
 333                        dump_stack((struct frame *)fp);
 334#else
 335                /* printk("NMI "); */
 336#endif
 337        }
 338        in_nmi--;
 339        return IRQ_HANDLED;
 340}
 341