/*1* Macintosh interrupts2*3* General design:4* In contrary to the Amiga and Atari platforms, the Mac hardware seems to5* exclusively use the autovector interrupts (the 'generic level0-level7'6* interrupts with exception vectors 0x19-0x1f). The following interrupt levels7* are used:8* 1 - VIA19* - slot 0: one second interrupt (CA2)10* - slot 1: VBlank (CA1)11* - slot 2: ADB data ready (SR full)12* - slot 3: ADB data (CB2)13* - slot 4: ADB clock (CB1)14* - slot 5: timer 215* - slot 6: timer 116* - slot 7: status of IRQ; signals 'any enabled int.'17*18* 2 - VIA2 or RBV19* - slot 0: SCSI DRQ (CA2)20* - slot 1: NUBUS IRQ (CA1) need to read port A to find which21* - slot 2: /EXP IRQ (only on IIci)22* - slot 3: SCSI IRQ (CB2)23* - slot 4: ASC IRQ (CB1)24* - slot 5: timer 2 (not on IIci)25* - slot 6: timer 1 (not on IIci)26* - slot 7: status of IRQ; signals 'any enabled int.'27*28* 2 - OSS (IIfx only?)29* - slot 0: SCSI interrupt30* - slot 1: Sound interrupt31*32* Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:33*34* 3 - unused (?)35*36* 4 - SCC37*38* 5 - unused (?)39* [serial errors or special conditions seem to raise level 640* interrupts on some models (LC4xx?)]41*42* 6 - off switch (?)43*44* For OSS Macintoshes (IIfx only at this point):45*46* 3 - Nubus interrupt47* - slot 0: Slot $948* - slot 1: Slot $A49* - slot 2: Slot $B50* - slot 3: Slot $C51* - slot 4: Slot $D52* - slot 5: Slot $E53*54* 4 - SCC IOP55*56* 5 - ISM IOP (ADB?)57*58* 6 - unused59*60* For PSC Macintoshes (660AV, 840AV):61*62* 3 - PSC level 363* - slot 0: MACE64*65* 4 - PSC level 466* - slot 1: SCC channel A interrupt67* - slot 2: SCC channel B interrupt68* - slot 3: MACE DMA69*70* 5 - PSC level 571*72* 6 - PSC level 673*74* Finally we have good 'ole level 7, the non-maskable interrupt:75*76* 7 - NMI (programmer's switch on the back of some Macs)77* Also RAM parity error on models which support it (IIc, IIfx?)78*79* The current interrupt logic looks something like this:80*81* - We install dispatchers for the autovector interrupts (1-7). These82* dispatchers are responsible for querying the hardware (the83* VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using84* this information a machspec interrupt number is generated by placing the85* index of the interrupt hardware into the low three bits and the original86* autovector interrupt number in the upper 5 bits. The handlers for the87* resulting machspec interrupt are then called.88*89* - Nubus is a special case because its interrupts are hidden behind two90* layers of hardware. Nubus interrupts come in as index 1 on VIA #2,91* which translates to IRQ number 17. In this spot we install _another_92* dispatcher. This dispatcher finds the interrupting slot number (9-F) and93* then forms a new machspec interrupt number as above with the slot number94* minus 9 in the low three bits and the pseudo-level 7 in the upper five95* bits. The handlers for this new machspec interrupt number are then96* called. This puts Nubus interrupts into the range 56-62.97*98* - The Baboon interrupts (used on some PowerBooks) are an even more special99* case. They're hidden behind the Nubus slot $C interrupt thus adding a100* third layer of indirection. Why oh why did the Apple engineers do that?101*102* - We support "fast" and "slow" handlers, just like the Amiga port. The103* fast handlers are called first and with all interrupts disabled. They104* are expected to execute quickly (hence the name). The slow handlers are105* called last with interrupts enabled and the interrupt level restored.106* They must therefore be reentrant.107*108* TODO:109*110*/111112#include <linux/module.h>113#include <linux/types.h>114#include <linux/kernel.h>115#include <linux/sched.h>116#include <linux/kernel_stat.h>117#include <linux/interrupt.h> /* for intr_count */118#include <linux/delay.h>119#include <linux/seq_file.h>120121#include <asm/system.h>122#include <asm/irq.h>123#include <asm/traps.h>124#include <asm/bootinfo.h>125#include <asm/macintosh.h>126#include <asm/mac_via.h>127#include <asm/mac_psc.h>128#include <asm/hwtest.h>129#include <asm/errno.h>130#include <asm/macints.h>131#include <asm/irq_regs.h>132#include <asm/mac_oss.h>133134#define SHUTUP_SONIC135136/*137* VIA/RBV hooks138*/139140extern void via_register_interrupts(void);141extern void via_irq_enable(int);142extern void via_irq_disable(int);143extern void via_irq_clear(int);144extern int via_irq_pending(int);145146/*147* OSS hooks148*/149150extern void oss_register_interrupts(void);151extern void oss_irq_enable(int);152extern void oss_irq_disable(int);153extern void oss_irq_clear(int);154extern int oss_irq_pending(int);155156/*157* PSC hooks158*/159160extern void psc_register_interrupts(void);161extern void psc_irq_enable(int);162extern void psc_irq_disable(int);163extern void psc_irq_clear(int);164extern int psc_irq_pending(int);165166/*167* IOP hooks168*/169170extern void iop_register_interrupts(void);171172/*173* Baboon hooks174*/175176extern int baboon_present;177178extern void baboon_register_interrupts(void);179extern void baboon_irq_enable(int);180extern void baboon_irq_disable(int);181extern void baboon_irq_clear(int);182183/*184* console_loglevel determines NMI handler function185*/186187irqreturn_t mac_nmi_handler(int, void *);188irqreturn_t mac_debug_handler(int, void *);189190/* #define DEBUG_MACINTS */191192void mac_enable_irq(unsigned int irq);193void mac_disable_irq(unsigned int irq);194195static struct irq_controller mac_irq_controller = {196.name = "mac",197.lock = __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock),198.enable = mac_enable_irq,199.disable = mac_disable_irq,200};201202void __init mac_init_IRQ(void)203{204#ifdef DEBUG_MACINTS205printk("mac_init_IRQ(): Setting things up...\n");206#endif207m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,208NUM_MAC_SOURCES - IRQ_USER);209/* Make sure the SONIC interrupt is cleared or things get ugly */210#ifdef SHUTUP_SONIC211printk("Killing onboard sonic... ");212/* This address should hopefully be mapped already */213if (hwreg_present((void*)(0x50f0a000))) {214*(long *)(0x50f0a014) = 0x7fffL;215*(long *)(0x50f0a010) = 0L;216}217printk("Done.\n");218#endif /* SHUTUP_SONIC */219220/*221* Now register the handlers for the master IRQ handlers222* at levels 1-7. Most of the work is done elsewhere.223*/224225if (oss_present)226oss_register_interrupts();227else228via_register_interrupts();229if (psc_present)230psc_register_interrupts();231if (baboon_present)232baboon_register_interrupts();233iop_register_interrupts();234if (request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",235mac_nmi_handler))236pr_err("Couldn't register NMI\n");237#ifdef DEBUG_MACINTS238printk("mac_init_IRQ(): Done!\n");239#endif240}241242/*243* mac_enable_irq - enable an interrupt source244* mac_disable_irq - disable an interrupt source245* mac_clear_irq - clears a pending interrupt246* mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)247*248* These routines are just dispatchers to the VIA/OSS/PSC routines.249*/250251void mac_enable_irq(unsigned int irq)252{253int irq_src = IRQ_SRC(irq);254255switch(irq_src) {256case 1:257via_irq_enable(irq);258break;259case 2:260case 7:261if (oss_present)262oss_irq_enable(irq);263else264via_irq_enable(irq);265break;266case 3:267case 5:268case 6:269if (psc_present)270psc_irq_enable(irq);271else if (oss_present)272oss_irq_enable(irq);273break;274case 4:275if (psc_present)276psc_irq_enable(irq);277break;278case 8:279if (baboon_present)280baboon_irq_enable(irq);281break;282}283}284285void mac_disable_irq(unsigned int irq)286{287int irq_src = IRQ_SRC(irq);288289switch(irq_src) {290case 1:291via_irq_disable(irq);292break;293case 2:294case 7:295if (oss_present)296oss_irq_disable(irq);297else298via_irq_disable(irq);299break;300case 3:301case 5:302case 6:303if (psc_present)304psc_irq_disable(irq);305else if (oss_present)306oss_irq_disable(irq);307break;308case 4:309if (psc_present)310psc_irq_disable(irq);311break;312case 8:313if (baboon_present)314baboon_irq_disable(irq);315break;316}317}318319void mac_clear_irq(unsigned int irq)320{321switch(IRQ_SRC(irq)) {322case 1:323via_irq_clear(irq);324break;325case 2:326case 7:327if (oss_present)328oss_irq_clear(irq);329else330via_irq_clear(irq);331break;332case 3:333case 5:334case 6:335if (psc_present)336psc_irq_clear(irq);337else if (oss_present)338oss_irq_clear(irq);339break;340case 4:341if (psc_present)342psc_irq_clear(irq);343break;344case 8:345if (baboon_present)346baboon_irq_clear(irq);347break;348}349}350351int mac_irq_pending(unsigned int irq)352{353switch(IRQ_SRC(irq)) {354case 1:355return via_irq_pending(irq);356case 2:357case 7:358if (oss_present)359return oss_irq_pending(irq);360else361return via_irq_pending(irq);362case 3:363case 5:364case 6:365if (psc_present)366return psc_irq_pending(irq);367else if (oss_present)368return oss_irq_pending(irq);369break;370case 4:371if (psc_present)372psc_irq_pending(irq);373break;374}375return 0;376}377EXPORT_SYMBOL(mac_irq_pending);378379static int num_debug[8];380381irqreturn_t mac_debug_handler(int irq, void *dev_id)382{383if (num_debug[irq] < 10) {384printk("DEBUG: Unexpected IRQ %d\n", irq);385num_debug[irq]++;386}387return IRQ_HANDLED;388}389390static int in_nmi;391static volatile int nmi_hold;392393irqreturn_t mac_nmi_handler(int irq, void *dev_id)394{395int i;396/*397* generate debug output on NMI switch if 'debug' kernel option given398* (only works with Penguin!)399*/400401in_nmi++;402for (i=0; i<100; i++)403udelay(1000);404405if (in_nmi == 1) {406nmi_hold = 1;407printk("... pausing, press NMI to resume ...");408} else {409printk(" ok!\n");410nmi_hold = 0;411}412413barrier();414415while (nmi_hold == 1)416udelay(1000);417418if (console_loglevel >= 8) {419#if 0420struct pt_regs *fp = get_irq_regs();421show_state();422printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);423printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",424fp->d0, fp->d1, fp->d2, fp->d3);425printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",426fp->d4, fp->d5, fp->a0, fp->a1);427428if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)429printk("Corrupted stack page\n");430printk("Process %s (pid: %d, stackpage=%08lx)\n",431current->comm, current->pid, current->kernel_stack_page);432if (intr_count == 1)433dump_stack((struct frame *)fp);434#else435/* printk("NMI "); */436#endif437}438in_nmi--;439return IRQ_HANDLED;440}441442443