2005-04-16 15:20:36 -07:00
/*
2011-01-05 12:47:28 +01:00
* Copyright IBM Corp . 2004 , 2010
2005-04-16 15:20:36 -07:00
* Author ( s ) : Martin Schwidefsky ( schwidefsky @ de . ibm . com ) ,
2007-02-05 21:16:44 +01:00
* Thomas Spatzier ( tspat @ de . ibm . com )
2005-04-16 15:20:36 -07:00
*
* This file contains interrupt related functions .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/kernel_stat.h>
# include <linux/interrupt.h>
# include <linux/seq_file.h>
# include <linux/cpu.h>
2007-02-05 21:16:44 +01:00
# include <linux/proc_fs.h>
# include <linux/profile.h>
2005-04-16 15:20:36 -07:00
2011-01-05 12:47:28 +01:00
struct irq_class {
char * name ;
char * desc ;
} ;
static const struct irq_class intrclass_names [ ] = {
{ . name = " EXT " } ,
{ . name = " I/O " } ,
{ . name = " CLK " , . desc = " [EXT] Clock Comparator " } ,
{ . name = " IPI " , . desc = " [EXT] Signal Processor " } ,
{ . name = " TMR " , . desc = " [EXT] CPU Timer " } ,
{ . name = " TAL " , . desc = " [EXT] Timing Alert " } ,
{ . name = " PFL " , . desc = " [EXT] Pseudo Page Fault " } ,
{ . name = " DSD " , . desc = " [EXT] DASD Diag " } ,
{ . name = " VRT " , . desc = " [EXT] Virtio " } ,
{ . name = " SCP " , . desc = " [EXT] Service Call " } ,
{ . name = " IUC " , . desc = " [EXT] IUCV " } ,
2011-01-05 12:47:29 +01:00
{ . name = " QAI " , . desc = " [I/O] QDIO Adapter Interrupt " } ,
{ . name = " QDI " , . desc = " [I/O] QDIO Interrupt " } ,
2011-01-05 12:47:28 +01:00
{ . name = " NMI " , . desc = " [NMI] Machine Check " } ,
} ;
2005-04-16 15:20:36 -07:00
/*
* show_interrupts is needed by / proc / interrupts .
*/
int show_interrupts ( struct seq_file * p , void * v )
{
int i = * ( loff_t * ) v , j ;
2008-05-15 16:52:39 +02:00
get_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
if ( i = = 0 ) {
seq_puts ( p , " " ) ;
for_each_online_cpu ( j )
seq_printf ( p , " CPU%d " , j ) ;
seq_putc ( p , ' \n ' ) ;
}
if ( i < NR_IRQS ) {
2011-01-05 12:47:28 +01:00
seq_printf ( p , " %s: " , intrclass_names [ i ] . name ) ;
2005-04-16 15:20:36 -07:00
# ifndef CONFIG_SMP
seq_printf ( p , " %10u " , kstat_irqs ( i ) ) ;
# else
for_each_online_cpu ( j )
seq_printf ( p , " %10u " , kstat_cpu ( j ) . irqs [ i ] ) ;
# endif
2011-01-05 12:47:28 +01:00
if ( intrclass_names [ i ] . desc )
seq_printf ( p , " %s " , intrclass_names [ i ] . desc ) ;
2005-04-16 15:20:36 -07:00
seq_putc ( p , ' \n ' ) ;
}
2008-05-15 16:52:39 +02:00
put_online_cpus ( ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/*
* For compatibilty only . S / 390 specific setup of interrupts et al . is done
* much later in init_channel_subsystem ( ) .
*/
void __init
init_IRQ ( void )
{
/* nothing... */
}
/*
* Switch to the asynchronous interrupt stack for softirq execution .
*/
asmlinkage void do_softirq ( void )
{
unsigned long flags , old , new ;
if ( in_interrupt ( ) )
return ;
local_irq_save ( flags ) ;
if ( local_softirq_pending ( ) ) {
/* Get current stack pointer. */
asm volatile ( " la %0,0(15) " : " = a " (old)) ;
/* Check against async. stack address range. */
new = S390_lowcore . async_stack ;
if ( ( ( new - old ) > > ( PAGE_SHIFT + THREAD_ORDER ) ) ! = 0 ) {
/* Need to switch to the async. stack. */
new - = STACK_FRAME_OVERHEAD ;
( ( struct stack_frame * ) new ) - > back_chain = old ;
asm volatile ( " la 15,0(%0) \n "
" basr 14,%2 \n "
" la 15,0(%1) \n "
: : " a " ( new ) , " a " ( old ) ,
" a " ( __do_softirq )
: " 0 " , " 1 " , " 2 " , " 3 " , " 4 " , " 5 " , " 14 " ,
" cc " , " memory " ) ;
} else
/* We are already on the async stack. */
__do_softirq ( ) ;
}
local_irq_restore ( flags ) ;
}
2007-02-05 21:16:44 +01:00
2009-02-11 10:37:29 +01:00
# ifdef CONFIG_PROC_FS
2007-02-05 21:16:44 +01:00
void init_irq_proc ( void )
{
struct proc_dir_entry * root_irq_dir ;
root_irq_dir = proc_mkdir ( " irq " , NULL ) ;
create_prof_cpu_mask ( root_irq_dir ) ;
}
2009-02-11 10:37:29 +01:00
# endif