2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / kernel / fiq . c
*
* Copyright ( C ) 1998 Russell King
* Copyright ( C ) 1998 , 1999 Phil Blundell
*
* FIQ support written by Philip Blundell < philb @ gnu . org > , 1998.
*
* FIQ support re - written by Russell King to be more generic
*
* We now properly support a method by which the FIQ handlers can
* be stacked onto the vector . We still do not support sharing
* the FIQ vector itself .
*
* Operation is as follows :
* 1. Owner A claims FIQ :
* - default_fiq relinquishes control .
* 2. Owner A :
* - inserts code .
* - sets any registers ,
* - enables FIQ .
* 3. Owner B claims FIQ :
* - if owner A has a relinquish function .
* - disable FIQs .
* - saves any registers .
* - returns zero .
* 4. Owner B :
* - inserts code .
* - sets any registers ,
* - enables FIQ .
* 5. Owner B releases FIQ :
* - Owner A is asked to reacquire FIQ :
* - inserts code .
* - restores saved registers .
* - enables FIQ .
* 6. Goto 3
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
2006-07-01 22:30:09 +01:00
# include <linux/interrupt.h>
2005-04-16 15:20:36 -07:00
# include <linux/seq_file.h>
# include <asm/cacheflush.h>
2012-03-28 18:30:01 +01:00
# include <asm/cp15.h>
2005-04-16 15:20:36 -07:00
# include <asm/fiq.h>
# include <asm/irq.h>
2010-09-13 16:03:21 +01:00
# include <asm/traps.h>
2005-04-16 15:20:36 -07:00
static unsigned long no_fiq_insn ;
/* Default reacquire function
* - we always relinquish FIQ control
* - we always reacquire FIQ control
*/
static int fiq_def_op ( void * ref , int relinquish )
{
if ( ! relinquish )
set_fiq_handler ( & no_fiq_insn , sizeof ( no_fiq_insn ) ) ;
return 0 ;
}
static struct fiq_handler default_owner = {
. name = " default " ,
. fiq_op = fiq_def_op ,
} ;
static struct fiq_handler * current_fiq = & default_owner ;
2010-11-15 14:33:51 +00:00
int show_fiq_list ( struct seq_file * p , int prec )
2005-04-16 15:20:36 -07:00
{
if ( current_fiq ! = & default_owner )
2010-11-15 14:33:51 +00:00
seq_printf ( p , " %*s: %s \n " , prec , " FIQ " ,
current_fiq - > name ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
void set_fiq_handler ( void * start , unsigned int length )
{
2010-09-13 16:03:21 +01:00
# if defined(CONFIG_CPU_USE_DOMAINS)
2005-04-16 15:20:36 -07:00
memcpy ( ( void * ) 0xffff001c , start , length ) ;
2010-09-13 16:03:21 +01:00
# else
memcpy ( vectors_page + 0x1c , start , length ) ;
# endif
2005-04-16 15:20:36 -07:00
flush_icache_range ( 0xffff001c , 0xffff001c + length ) ;
if ( ! vectors_high ( ) )
flush_icache_range ( 0x1c , 0x1c + length ) ;
}
int claim_fiq ( struct fiq_handler * f )
{
int ret = 0 ;
if ( current_fiq ) {
ret = - EBUSY ;
if ( current_fiq - > fiq_op ! = NULL )
ret = current_fiq - > fiq_op ( current_fiq - > dev_id , 1 ) ;
}
if ( ! ret ) {
f - > next = current_fiq ;
current_fiq = f ;
}
return ret ;
}
void release_fiq ( struct fiq_handler * f )
{
if ( current_fiq ! = f ) {
printk ( KERN_ERR " %s FIQ trying to release %s FIQ \n " ,
f - > name , current_fiq - > name ) ;
dump_stack ( ) ;
return ;
}
do
current_fiq = current_fiq - > next ;
while ( current_fiq - > fiq_op ( current_fiq - > dev_id , 0 ) ) ;
}
2012-06-28 14:42:08 +08:00
static int fiq_start ;
2005-04-16 15:20:36 -07:00
void enable_fiq ( int fiq )
{
2012-06-28 14:42:08 +08:00
enable_irq ( fiq + fiq_start ) ;
2005-04-16 15:20:36 -07:00
}
void disable_fiq ( int fiq )
{
2012-06-28 14:42:08 +08:00
disable_irq ( fiq + fiq_start ) ;
2005-04-16 15:20:36 -07:00
}
EXPORT_SYMBOL ( set_fiq_handler ) ;
2011-05-23 12:22:10 +01:00
EXPORT_SYMBOL ( __set_fiq_regs ) ; /* defined in fiqasm.S */
EXPORT_SYMBOL ( __get_fiq_regs ) ; /* defined in fiqasm.S */
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( claim_fiq ) ;
EXPORT_SYMBOL ( release_fiq ) ;
EXPORT_SYMBOL ( enable_fiq ) ;
EXPORT_SYMBOL ( disable_fiq ) ;
2012-06-28 14:42:08 +08:00
void __init init_FIQ ( int start )
2005-04-16 15:20:36 -07:00
{
no_fiq_insn = * ( unsigned long * ) 0xffff001c ;
2012-06-28 14:42:08 +08:00
fiq_start = start ;
2005-04-16 15:20:36 -07:00
}