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>
2008-08-13 02:09:03 +04:00
# include <linux/seq_file.h>
2005-04-17 02:20:36 +04:00
# 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
2008-08-13 02:09:03 +04:00
static int irq_affinity_proc_show ( struct seq_file * m , void * v )
2005-04-17 02:20:36 +04:00
{
2008-08-13 02:09:03 +04:00
struct irq_desc * desc = irq_desc + ( long ) m - > private ;
2007-07-21 19:09:54 +04:00
cpumask_t * mask = & desc - > affinity ;
# ifdef CONFIG_GENERIC_PENDING_IRQ
if ( desc - > status & IRQ_MOVE_PENDING )
mask = & desc - > pending_mask ;
# endif
2008-08-13 02:09:03 +04:00
seq_cpumask ( m , mask ) ;
seq_putc ( m , ' \n ' ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
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 ;
2008-08-13 02:09:03 +04:00
static ssize_t irq_affinity_proc_write ( struct file * file ,
const char __user * buffer , size_t count , loff_t * pos )
2005-04-17 02:20:36 +04:00
{
2008-08-13 02:09:03 +04:00
unsigned int irq = ( int ) ( long ) PDE ( file - > f_path . dentry - > d_inode ) - > data ;
2008-05-29 22:02:52 +04:00
cpumask_t new_value ;
2008-08-13 02:09:03 +04:00
int err ;
2005-04-17 02:20:36 +04:00
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 .
*/
2008-05-29 22:02:52 +04:00
if ( ! cpus_intersects ( new_value , cpu_online_map ) )
2006-01-06 11:12:21 +03:00
/* Special case for empty set - allow the architecture
code to set default SMP affinity . */
2008-08-13 02:09:03 +04:00
return irq_select_affinity ( irq ) ? - EINVAL : 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
2008-08-13 02:09:03 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
2008-08-13 02:09:03 +04:00
static int irq_affinity_proc_open ( struct inode * inode , struct file * file )
2008-05-29 22:02:52 +04:00
{
2008-08-13 02:09:03 +04:00
return single_open ( file , irq_affinity_proc_show , PDE ( inode ) - > data ) ;
2008-05-29 22:02:52 +04:00
}
2008-08-13 02:09:03 +04:00
static const struct file_operations irq_affinity_proc_fops = {
. open = irq_affinity_proc_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
. write = irq_affinity_proc_write ,
} ;
static int default_affinity_show ( struct seq_file * m , void * v )
{
seq_cpumask ( m , & irq_default_affinity ) ;
seq_putc ( m , ' \n ' ) ;
return 0 ;
}
static ssize_t default_affinity_write ( struct file * file ,
const char __user * buffer , size_t count , loff_t * ppos )
2008-05-29 22:02:52 +04:00
{
cpumask_t new_value ;
2008-08-13 02:09:03 +04:00
int err ;
2008-05-29 22:02:52 +04:00
err = cpumask_parse_user ( buffer , count , new_value ) ;
if ( err )
return err ;
if ( ! is_affinity_mask_valid ( new_value ) )
return - EINVAL ;
/*
* 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 .
*/
if ( ! cpus_intersects ( new_value , cpu_online_map ) )
return - EINVAL ;
irq_default_affinity = new_value ;
2008-08-13 02:09:03 +04:00
return count ;
2008-05-29 22:02:52 +04:00
}
2008-08-13 02:09:03 +04:00
static int default_affinity_open ( struct inode * inode , struct file * file )
{
return single_open ( file , default_affinity_show , NULL ) ;
}
static const struct file_operations default_affinity_proc_fops = {
. open = default_affinity_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
. write = default_affinity_write ,
} ;
2005-04-17 02:20:36 +04:00
# endif
2008-01-30 15:32:48 +03:00
static int irq_spurious_read ( char * page , char * * start , off_t off ,
int count , int * eof , void * data )
{
struct irq_desc * d = & irq_desc [ ( long ) data ] ;
return sprintf ( page , " count %u \n "
" unhandled %u \n "
" last_unhandled %u ms \n " ,
d - > irq_count ,
d - > irqs_unhandled ,
jiffies_to_msecs ( d - > last_unhandled ) ) ;
}
2005-04-17 02:20:36 +04:00
# 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 ] ;
2008-01-30 15:32:48 +03:00
struct proc_dir_entry * entry ;
2005-04-17 02:20:36 +04:00
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
2008-08-13 02:09:03 +04:00
/* create /proc/irq/<irq>/smp_affinity */
proc_create_data ( " smp_affinity " , 0600 , irq_desc [ irq ] . dir ,
& irq_affinity_proc_fops , ( void * ) ( long ) irq ) ;
2005-04-17 02:20:36 +04:00
# endif
2008-01-30 15:32:48 +03:00
entry = create_proc_entry ( " spurious " , 0444 , irq_desc [ irq ] . dir ) ;
if ( entry ) {
entry - > data = ( void * ) ( long ) irq ;
entry - > read_proc = irq_spurious_read ;
}
2005-04-17 02:20:36 +04:00
}
# 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
}
2008-05-29 22:02:52 +04:00
void register_default_affinity_proc ( void )
{
# ifdef CONFIG_SMP
2008-08-13 02:09:03 +04:00
proc_create ( " irq/default_smp_affinity " , 0600 , NULL ,
& default_affinity_proc_fops ) ;
2008-05-29 22:02:52 +04:00
# endif
}
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 ;
2008-05-29 22:02:52 +04:00
register_default_affinity_proc ( ) ;
2005-04-17 02:20:36 +04:00
/*
* Create entries for all existing IRQs .
*/
2008-08-20 07:49:47 +04:00
for ( i = 0 ; i < nr_irqs ; i + + )
2005-04-17 02:20:36 +04:00
register_irq_proc ( i ) ;
}