2005-04-17 02:20:36 +04:00
/*
* linux / kernel / irq / proc . c
*
* Copyright ( C ) 1992 , 1998 - 2004 Linus Torvalds , Ingo Molnar
*
* This file contains the / proc / irq / handling code .
*/
# include <linux/irq.h>
# include <linux/proc_fs.h>
# include <linux/interrupt.h>
2006-01-08 12:02:17 +03:00
# include "internals.h"
2006-06-29 13:24:42 +04:00
static struct proc_dir_entry * root_irq_dir ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SMP
static int irq_affinity_read_proc ( char * page , char * * start , off_t off ,
int count , int * eof , void * data )
{
2007-07-21 19:09:54 +04:00
struct irq_desc * desc = irq_desc + ( long ) data ;
cpumask_t * mask = & desc - > affinity ;
int len ;
# ifdef CONFIG_GENERIC_PENDING_IRQ
if ( desc - > status & IRQ_MOVE_PENDING )
mask = & desc - > pending_mask ;
# endif
len = cpumask_scnprintf ( page , count , * mask ) ;
2005-04-17 02:20:36 +04:00
if ( count - len < 2 )
return - EINVAL ;
len + = sprintf ( page + len , " \n " ) ;
return len ;
}
2007-05-11 09:42:44 +04:00
# ifndef is_affinity_mask_valid
# define is_affinity_mask_valid(val) 1
# endif
2005-04-17 02:20:36 +04:00
int no_irq_affinity ;
static int irq_affinity_write_proc ( struct file * file , const char __user * buffer ,
unsigned long count , void * data )
{
unsigned int irq = ( int ) ( long ) data , full_count = count , err ;
cpumask_t new_value , tmp ;
2006-12-08 13:35:58 +03:00
if ( ! irq_desc [ irq ] . chip - > set_affinity | | no_irq_affinity | |
2007-02-16 12:27:24 +03:00
irq_balancing_disabled ( irq ) )
2005-04-17 02:20:36 +04:00
return - EIO ;
2006-10-11 12:21:55 +04:00
err = cpumask_parse_user ( buffer , count , new_value ) ;
2005-04-17 02:20:36 +04:00
if ( err )
return err ;
2007-05-11 09:42:44 +04:00
if ( ! is_affinity_mask_valid ( new_value ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/*
* Do not allow disabling IRQs completely - it ' s a too easy
* way to make the system unusable accidentally : - ) At least
* one online CPU still has to be targeted .
*/
cpus_and ( tmp , new_value , cpu_online_map ) ;
if ( cpus_empty ( tmp ) )
2006-01-06 11:12:21 +03:00
/* Special case for empty set - allow the architecture
code to set default SMP affinity . */
return select_smp_affinity ( irq ) ? - EINVAL : full_count ;
2005-04-17 02:20:36 +04:00
2007-02-16 12:27:25 +03:00
irq_set_affinity ( irq , new_value ) ;
2005-04-17 02:20:36 +04:00
return full_count ;
}
# endif
# define MAX_NAMELEN 128
static int name_unique ( unsigned int irq , struct irqaction * new_action )
{
struct irq_desc * desc = irq_desc + irq ;
struct irqaction * action ;
2007-05-08 11:27:31 +04:00
unsigned long flags ;
int ret = 1 ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:27:31 +04:00
spin_lock_irqsave ( & desc - > lock , flags ) ;
for ( action = desc - > action ; action ; action = action - > next ) {
2005-04-17 02:20:36 +04:00
if ( ( action ! = new_action ) & & action - > name & &
2007-05-08 11:27:31 +04:00
! strcmp ( new_action - > name , action - > name ) ) {
ret = 0 ;
break ;
}
}
spin_unlock_irqrestore ( & desc - > lock , flags ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
void register_handler_proc ( unsigned int irq , struct irqaction * action )
{
char name [ MAX_NAMELEN ] ;
2006-06-29 13:24:42 +04:00
if ( ! irq_desc [ irq ] . dir | | action - > dir | | ! action - > name | |
2005-04-17 02:20:36 +04:00
! name_unique ( irq , action ) )
return ;
memset ( name , 0 , MAX_NAMELEN ) ;
snprintf ( name , MAX_NAMELEN , " %s " , action - > name ) ;
/* create /proc/irq/1234/handler/ */
2006-06-29 13:24:42 +04:00
action - > dir = proc_mkdir ( name , irq_desc [ irq ] . dir ) ;
2005-04-17 02:20:36 +04:00
}
# undef MAX_NAMELEN
# define MAX_NAMELEN 10
void register_irq_proc ( unsigned int irq )
{
char name [ MAX_NAMELEN ] ;
if ( ! root_irq_dir | |
2006-06-29 13:24:57 +04:00
( irq_desc [ irq ] . chip = = & no_irq_chip ) | |
2006-06-29 13:24:42 +04:00
irq_desc [ irq ] . dir )
2005-04-17 02:20:36 +04:00
return ;
memset ( name , 0 , MAX_NAMELEN ) ;
sprintf ( name , " %d " , irq ) ;
/* create /proc/irq/1234 */
2006-06-29 13:24:42 +04:00
irq_desc [ irq ] . dir = proc_mkdir ( name , root_irq_dir ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SMP
{
struct proc_dir_entry * entry ;
/* create /proc/irq/<irq>/smp_affinity */
2006-06-29 13:24:42 +04:00
entry = create_proc_entry ( " smp_affinity " , 0600 , irq_desc [ irq ] . dir ) ;
2005-04-17 02:20:36 +04:00
if ( entry ) {
entry - > data = ( void * ) ( long ) irq ;
entry - > read_proc = irq_affinity_read_proc ;
entry - > write_proc = irq_affinity_write_proc ;
}
}
# endif
}
# undef MAX_NAMELEN
void unregister_handler_proc ( unsigned int irq , struct irqaction * action )
{
if ( action - > dir )
2006-06-29 13:24:42 +04:00
remove_proc_entry ( action - > dir - > name , irq_desc [ irq ] . dir ) ;
2005-04-17 02:20:36 +04:00
}
void init_irq_proc ( void )
{
int i ;
/* create /proc/irq */
root_irq_dir = proc_mkdir ( " irq " , NULL ) ;
if ( ! root_irq_dir )
return ;
/*
* Create entries for all existing IRQs .
*/
for ( i = 0 ; i < NR_IRQS ; i + + )
register_irq_proc ( i ) ;
}