2005-04-16 15:20:36 -07:00
/*
* Macintosh interrupts
*
* General design :
* In contrary to the Amiga and Atari platforms , the Mac hardware seems to
* exclusively use the autovector interrupts ( the ' generic level0 - level7 '
* interrupts with exception vectors 0x19 - 0x1f ) . The following interrupt levels
* are used :
* 1 - VIA1
* - slot 0 : one second interrupt ( CA2 )
* - slot 1 : VBlank ( CA1 )
* - slot 2 : ADB data ready ( SR full )
* - slot 3 : ADB data ( CB2 )
* - slot 4 : ADB clock ( CB1 )
* - slot 5 : timer 2
* - slot 6 : timer 1
* - slot 7 : status of IRQ ; signals ' any enabled int . '
*
* 2 - VIA2 or RBV
* - slot 0 : SCSI DRQ ( CA2 )
* - slot 1 : NUBUS IRQ ( CA1 ) need to read port A to find which
* - slot 2 : / EXP IRQ ( only on IIci )
* - slot 3 : SCSI IRQ ( CB2 )
* - slot 4 : ASC IRQ ( CB1 )
* - slot 5 : timer 2 ( not on IIci )
* - slot 6 : timer 1 ( not on IIci )
* - slot 7 : status of IRQ ; signals ' any enabled int . '
*
* Levels 3 - 6 vary by machine type . For VIA or RBV Macintoshes :
*
* 3 - unused ( ? )
*
2009-11-17 20:06:48 +11:00
* 4 - SCC
2005-04-16 15:20:36 -07:00
*
* 5 - unused ( ? )
* [ serial errors or special conditions seem to raise level 6
* interrupts on some models ( LC4xx ? ) ]
*
* 6 - off switch ( ? )
*
2011-10-24 01:11:16 +11:00
* Machines with Quadra - like VIA hardware , except PSC and PMU machines , support
* an alternate interrupt mapping , as used by A / UX . It spreads ethernet and
* sound out to their own autovector IRQs and gives VIA1 a higher priority :
*
* 1 - unused ( ? )
*
* 3 - on - board SONIC
*
* 5 - Apple Sound Chip ( ASC )
*
* 6 - VIA1
*
2011-10-24 01:11:18 +11:00
* For OSS Macintoshes ( IIfx only ) , we apply an interrupt mapping similar to
* the Quadra ( A / UX ) mapping :
2005-04-16 15:20:36 -07:00
*
2011-10-24 01:11:18 +11:00
* 1 - ISM IOP ( ADB )
2005-04-16 15:20:36 -07:00
*
2011-10-24 01:11:18 +11:00
* 2 - SCSI
2005-04-16 15:20:36 -07:00
*
2011-10-24 01:11:18 +11:00
* 3 - NuBus
2005-04-16 15:20:36 -07:00
*
2011-10-24 01:11:18 +11:00
* 4 - SCC IOP
*
* 6 - VIA1
2005-04-16 15:20:36 -07:00
*
* For PSC Macintoshes ( 660 AV , 840 AV ) :
*
* 3 - PSC level 3
* - slot 0 : MACE
*
* 4 - PSC level 4
* - slot 1 : SCC channel A interrupt
* - slot 2 : SCC channel B interrupt
* - slot 3 : MACE DMA
*
* 5 - PSC level 5
*
* 6 - PSC level 6
*
* Finally we have good ' ole level 7 , the non - maskable interrupt :
*
* 7 - NMI ( programmer ' s switch on the back of some Macs )
* Also RAM parity error on models which support it ( IIc , IIfx ? )
*
* The current interrupt logic looks something like this :
*
* - We install dispatchers for the autovector interrupts ( 1 - 7 ) . These
* dispatchers are responsible for querying the hardware ( the
* VIA / RBV / OSS / PSC chips ) to determine the actual interrupt source . Using
* this information a machspec interrupt number is generated by placing the
* index of the interrupt hardware into the low three bits and the original
* autovector interrupt number in the upper 5 bits . The handlers for the
* resulting machspec interrupt are then called .
*
* - Nubus is a special case because its interrupts are hidden behind two
* layers of hardware . Nubus interrupts come in as index 1 on VIA # 2 ,
* which translates to IRQ number 17. In this spot we install _another_
* dispatcher . This dispatcher finds the interrupting slot number ( 9 - F ) and
* then forms a new machspec interrupt number as above with the slot number
* minus 9 in the low three bits and the pseudo - level 7 in the upper five
* bits . The handlers for this new machspec interrupt number are then
* called . This puts Nubus interrupts into the range 56 - 62.
*
* - The Baboon interrupts ( used on some PowerBooks ) are an even more special
* case . They ' re hidden behind the Nubus slot $ C interrupt thus adding a
* third layer of indirection . Why oh why did the Apple engineers do that ?
*
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/sched.h>
2017-02-08 18:51:35 +01:00
# include <linux/sched/debug.h>
2011-10-24 01:11:15 +11:00
# include <linux/interrupt.h>
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
# include <linux/delay.h>
# include <asm/irq.h>
# include <asm/macintosh.h>
2011-10-24 01:11:15 +11:00
# include <asm/macints.h>
2005-04-16 15:20:36 -07:00
# include <asm/mac_via.h>
# include <asm/mac_psc.h>
2011-10-24 01:11:15 +11:00
# include <asm/mac_oss.h>
# include <asm/mac_iop.h>
# include <asm/mac_baboon.h>
2005-04-16 15:20:36 -07:00
# include <asm/hwtest.h>
2006-10-07 14:16:45 +01:00
# include <asm/irq_regs.h>
2005-04-16 15:20:36 -07:00
2017-01-02 04:53:54 -05:00
extern void show_registers ( struct pt_regs * ) ;
2005-04-16 15:20:36 -07:00
2006-10-07 14:16:45 +01:00
irqreturn_t mac_nmi_handler ( int , void * ) ;
2005-04-16 15:20:36 -07:00
2011-10-24 01:11:17 +11:00
static unsigned int mac_irq_startup ( struct irq_data * ) ;
static void mac_irq_shutdown ( struct irq_data * ) ;
2011-04-13 22:31:28 +02:00
static struct irq_chip mac_irq_chip = {
2006-06-25 05:47:04 -07:00
. name = " mac " ,
2011-04-17 22:53:04 +02:00
. irq_enable = mac_irq_enable ,
. irq_disable = mac_irq_disable ,
2011-10-24 01:11:17 +11:00
. irq_startup = mac_irq_startup ,
. irq_shutdown = mac_irq_shutdown ,
2006-06-25 05:47:04 -07:00
} ;
2007-07-20 04:33:28 +01:00
void __init mac_init_IRQ ( void )
2005-04-16 15:20:36 -07:00
{
2011-06-01 11:15:21 +02:00
m68k_setup_irq_controller ( & mac_irq_chip , handle_simple_irq , IRQ_USER ,
2006-06-25 05:47:04 -07:00
NUM_MAC_SOURCES - IRQ_USER ) ;
2005-04-16 15:20:36 -07:00
/*
* Now register the handlers for the master IRQ handlers
* at levels 1 - 7. Most of the work is done elsewhere .
*/
2006-06-25 05:47:04 -07:00
if ( oss_present )
2005-04-16 15:20:36 -07:00
oss_register_interrupts ( ) ;
2006-06-25 05:47:04 -07:00
else
2005-04-16 15:20:36 -07:00
via_register_interrupts ( ) ;
2015-09-29 09:27:22 +02:00
if ( psc )
2006-06-25 05:47:04 -07:00
psc_register_interrupts ( ) ;
if ( baboon_present )
baboon_register_interrupts ( ) ;
2005-04-16 15:20:36 -07:00
iop_register_interrupts ( ) ;
2008-12-30 14:02:27 +01:00
if ( request_irq ( IRQ_AUTO_7 , mac_nmi_handler , 0 , " NMI " ,
mac_nmi_handler ) )
pr_err ( " Couldn't register NMI \n " ) ;
2005-04-16 15:20:36 -07:00
}
/*
2011-09-11 23:40:50 +10:00
* mac_irq_enable - enable an interrupt source
* mac_irq_disable - disable an interrupt source
2005-04-16 15:20:36 -07:00
*
* These routines are just dispatchers to the VIA / OSS / PSC routines .
*/
2011-09-11 23:40:50 +10:00
void mac_irq_enable ( struct irq_data * data )
2005-04-16 15:20:36 -07:00
{
2011-09-11 23:40:50 +10:00
int irq = data - > irq ;
2006-06-25 05:47:04 -07:00
int irq_src = IRQ_SRC ( irq ) ;
2005-04-16 15:20:36 -07:00
switch ( irq_src ) {
2006-06-25 05:47:04 -07:00
case 1 :
case 2 :
case 7 :
if ( oss_present )
oss_irq_enable ( irq ) ;
else
via_irq_enable ( irq ) ;
break ;
case 3 :
2011-10-24 01:11:18 +11:00
case 4 :
2006-06-25 05:47:04 -07:00
case 5 :
case 6 :
2015-09-29 09:27:22 +02:00
if ( psc )
2006-06-25 05:47:04 -07:00
psc_irq_enable ( irq ) ;
else if ( oss_present )
oss_irq_enable ( irq ) ;
2009-11-17 20:06:48 +11:00
break ;
2006-06-25 05:47:04 -07:00
case 8 :
if ( baboon_present )
baboon_irq_enable ( irq ) ;
break ;
2005-04-16 15:20:36 -07:00
}
}
2011-09-11 23:40:50 +10:00
void mac_irq_disable ( struct irq_data * data )
2005-04-16 15:20:36 -07:00
{
2011-09-11 23:40:50 +10:00
int irq = data - > irq ;
2006-06-25 05:47:04 -07:00
int irq_src = IRQ_SRC ( irq ) ;
2005-04-16 15:20:36 -07:00
switch ( irq_src ) {
2006-06-25 05:47:04 -07:00
case 1 :
case 2 :
case 7 :
if ( oss_present )
oss_irq_disable ( irq ) ;
else
via_irq_disable ( irq ) ;
break ;
case 3 :
2011-10-24 01:11:18 +11:00
case 4 :
2006-06-25 05:47:04 -07:00
case 5 :
case 6 :
2015-09-29 09:27:22 +02:00
if ( psc )
2006-06-25 05:47:04 -07:00
psc_irq_disable ( irq ) ;
else if ( oss_present )
oss_irq_disable ( irq ) ;
2009-11-17 20:06:48 +11:00
break ;
2006-06-25 05:47:04 -07:00
case 8 :
if ( baboon_present )
baboon_irq_disable ( irq ) ;
break ;
2005-04-16 15:20:36 -07:00
}
}
2011-10-24 01:11:17 +11:00
static unsigned int mac_irq_startup ( struct irq_data * data )
{
int irq = data - > irq ;
if ( IRQ_SRC ( irq ) = = 7 & & ! oss_present )
via_nubus_irq_startup ( irq ) ;
else
mac_irq_enable ( data ) ;
return 0 ;
}
static void mac_irq_shutdown ( struct irq_data * data )
{
int irq = data - > irq ;
if ( IRQ_SRC ( irq ) = = 7 & & ! oss_present )
via_nubus_irq_shutdown ( irq ) ;
else
mac_irq_disable ( data ) ;
}
2017-01-02 04:53:54 -05:00
static volatile int in_nmi ;
2005-04-16 15:20:36 -07:00
2006-10-07 14:16:45 +01:00
irqreturn_t mac_nmi_handler ( int irq , void * dev_id )
2005-04-16 15:20:36 -07:00
{
2017-01-02 04:53:54 -05:00
if ( in_nmi )
return IRQ_HANDLED ;
in_nmi = 1 ;
2005-04-16 15:20:36 -07:00
2017-01-02 04:53:54 -05:00
pr_info ( " Non-Maskable Interrupt \n " ) ;
show_registers ( get_irq_regs ( ) ) ;
2005-04-16 15:20:36 -07:00
2017-01-02 04:53:54 -05:00
in_nmi = 0 ;
2005-04-16 15:20:36 -07:00
return IRQ_HANDLED ;
}