2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) 2003 Ralf Baechle
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* Handler for RM9000 extended interrupts . These are a non - standard
* feature so we handle them separately from standard interrupts .
*/
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <asm/irq_cpu.h>
# include <asm/mipsregs.h>
# include <asm/system.h>
static inline void unmask_rm9k_irq ( unsigned int irq )
{
2007-01-08 02:14:29 +09:00
set_c0_intcontrol ( 0x1000 < < ( irq - RM9K_CPU_IRQ_BASE ) ) ;
2005-04-16 15:20:36 -07:00
}
static inline void mask_rm9k_irq ( unsigned int irq )
{
2007-01-08 02:14:29 +09:00
clear_c0_intcontrol ( 0x1000 < < ( irq - RM9K_CPU_IRQ_BASE ) ) ;
2005-04-16 15:20:36 -07:00
}
static inline void rm9k_cpu_irq_enable ( unsigned int irq )
{
unsigned long flags ;
local_irq_save ( flags ) ;
unmask_rm9k_irq ( irq ) ;
local_irq_restore ( flags ) ;
}
/*
* Performance counter interrupts are global on all processors .
*/
static void local_rm9k_perfcounter_irq_startup ( void * args )
{
unsigned int irq = ( unsigned int ) args ;
rm9k_cpu_irq_enable ( irq ) ;
}
static unsigned int rm9k_perfcounter_irq_startup ( unsigned int irq )
{
2008-05-09 09:39:44 +02:00
on_each_cpu ( local_rm9k_perfcounter_irq_startup , ( void * ) irq , 1 ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static void local_rm9k_perfcounter_irq_shutdown ( void * args )
{
unsigned int irq = ( unsigned int ) args ;
unsigned long flags ;
local_irq_save ( flags ) ;
mask_rm9k_irq ( irq ) ;
local_irq_restore ( flags ) ;
}
static void rm9k_perfcounter_irq_shutdown ( unsigned int irq )
{
2008-05-09 09:39:44 +02:00
on_each_cpu ( local_rm9k_perfcounter_irq_shutdown , ( void * ) irq , 1 ) ;
2005-04-16 15:20:36 -07:00
}
2006-07-02 14:41:42 +01:00
static struct irq_chip rm9k_irq_controller = {
2007-01-15 00:07:25 +09:00
. name = " RM9000 " ,
2006-11-02 02:08:36 +09:00
. ack = mask_rm9k_irq ,
. mask = mask_rm9k_irq ,
. mask_ack = mask_rm9k_irq ,
. unmask = unmask_rm9k_irq ,
2008-02-11 23:42:12 +01:00
. eoi = unmask_rm9k_irq
2005-04-16 15:20:36 -07:00
} ;
2006-07-02 14:41:42 +01:00
static struct irq_chip rm9k_perfcounter_irq = {
2007-01-15 00:07:25 +09:00
. name = " RM9000 " ,
2005-02-28 13:39:57 +00:00
. startup = rm9k_perfcounter_irq_startup ,
. shutdown = rm9k_perfcounter_irq_shutdown ,
2006-11-02 02:08:36 +09:00
. ack = mask_rm9k_irq ,
. mask = mask_rm9k_irq ,
. mask_ack = mask_rm9k_irq ,
. unmask = unmask_rm9k_irq ,
2005-04-16 15:20:36 -07:00
} ;
unsigned int rm9000_perfcount_irq ;
EXPORT_SYMBOL ( rm9000_perfcount_irq ) ;
2007-01-08 02:14:29 +09:00
void __init rm9k_cpu_irq_init ( void )
2005-04-16 15:20:36 -07:00
{
2007-01-08 02:14:29 +09:00
int base = RM9K_CPU_IRQ_BASE ;
2005-04-16 15:20:36 -07:00
int i ;
clear_c0_intcontrol ( 0x0000f000 ) ; /* Mask all */
2006-11-02 02:08:36 +09:00
for ( i = base ; i < base + 4 ; i + + )
2006-11-14 01:13:18 +09:00
set_irq_chip_and_handler ( i , & rm9k_irq_controller ,
handle_level_irq ) ;
2005-04-16 15:20:36 -07:00
rm9000_perfcount_irq = base + 1 ;
2006-11-14 01:13:18 +09:00
set_irq_chip_and_handler ( rm9000_perfcount_irq , & rm9k_perfcounter_irq ,
2007-11-15 19:37:15 +00:00
handle_percpu_irq ) ;
2005-04-16 15:20:36 -07:00
}