2005-04-17 02:20:36 +04:00
/*
* linux / kernel / irq / autoprobe . c
*
* Copyright ( C ) 1992 , 1998 - 2004 Linus Torvalds , Ingo Molnar
*
* This file contains the interrupt probing code and driver APIs .
*/
# include <linux/irq.h>
# include <linux/module.h>
# include <linux/interrupt.h>
2005-06-29 07:44:42 +04:00
# include <linux/delay.h>
2009-01-07 19:45:46 +03:00
# include <linux/async.h>
2005-04-17 02:20:36 +04:00
2006-06-29 13:24:54 +04:00
# include "internals.h"
2005-04-17 02:20:36 +04:00
/*
* Autodetection depends on the fact that any interrupt that
* comes in on to an unassigned handler will get stuck with
2011-02-08 13:39:15 +03:00
* " IRQS_WAITING " cleared and the interrupt disabled .
2005-04-17 02:20:36 +04:00
*/
2006-06-29 13:24:37 +04:00
static DEFINE_MUTEX ( probing_active ) ;
2005-04-17 02:20:36 +04:00
/**
* probe_irq_on - begin an interrupt autodetect
*
* Commence probing for an interrupt . The interrupts are scanned
* and a mask of potential interrupt lines is returned .
*
*/
unsigned long probe_irq_on ( void )
{
2006-06-29 13:24:40 +04:00
struct irq_desc * desc ;
2008-10-16 16:19:04 +04:00
unsigned long mask = 0 ;
int i ;
2005-04-17 02:20:36 +04:00
2009-01-07 19:45:46 +03:00
/*
* quiesce the kernel , or at least the asynchronous portion
*/
async_synchronize_full ( ) ;
2006-06-29 13:24:37 +04:00
mutex_lock ( & probing_active ) ;
2005-04-17 02:20:36 +04:00
/*
* something may have generated an irq long ago and we want to
* flush such a longstanding irq before considering it as spurious .
*/
2008-10-16 16:19:04 +04:00
for_each_irq_desc_reverse ( i , desc ) {
2009-11-17 18:46:45 +03:00
raw_spin_lock_irq ( & desc - > lock ) ;
2011-02-09 16:44:17 +03:00
if ( ! desc - > action & & irq_settings_can_probe ( desc ) ) {
2006-06-29 13:24:51 +04:00
/*
* Some chips need to know about probing in
* progress :
*/
2010-09-27 16:45:47 +04:00
if ( desc - > irq_data . chip - > irq_set_type )
desc - > irq_data . chip - > irq_set_type ( & desc - > irq_data ,
IRQ_TYPE_PROBE ) ;
2017-06-20 02:37:49 +03:00
irq_startup ( desc , IRQ_NORESEND , IRQ_START_FORCE ) ;
2006-06-29 13:24:51 +04:00
}
2009-11-17 18:46:45 +03:00
raw_spin_unlock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
}
/* Wait for longstanding interrupts to trigger. */
2005-06-29 07:44:42 +04:00
msleep ( 20 ) ;
2005-04-17 02:20:36 +04:00
/*
* enable any unassigned irqs
* ( we must startup again here because if a longstanding irq
* happened in the previous stage , it may have masked itself )
*/
2008-10-16 16:19:04 +04:00
for_each_irq_desc_reverse ( i , desc ) {
2009-11-17 18:46:45 +03:00
raw_spin_lock_irq ( & desc - > lock ) ;
2011-02-09 16:44:17 +03:00
if ( ! desc - > action & & irq_settings_can_probe ( desc ) ) {
2011-02-08 13:39:15 +03:00
desc - > istate | = IRQS_AUTODETECT | IRQS_WAITING ;
2017-06-20 02:37:49 +03:00
if ( irq_startup ( desc , IRQ_NORESEND , IRQ_START_FORCE ) )
2011-02-08 14:17:57 +03:00
desc - > istate | = IRQS_PENDING ;
2005-04-17 02:20:36 +04:00
}
2009-11-17 18:46:45 +03:00
raw_spin_unlock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Wait for spurious interrupts to trigger
*/
2005-06-29 07:44:42 +04:00
msleep ( 100 ) ;
2005-04-17 02:20:36 +04:00
/*
* Now filter out any obviously spurious interrupts
*/
2008-10-16 16:19:04 +04:00
for_each_irq_desc ( i , desc ) {
2009-11-17 18:46:45 +03:00
raw_spin_lock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
2011-02-07 22:25:25 +03:00
if ( desc - > istate & IRQS_AUTODETECT ) {
2005-04-17 02:20:36 +04:00
/* It triggered already - consider it spurious. */
2011-02-08 13:39:15 +03:00
if ( ! ( desc - > istate & IRQS_WAITING ) ) {
2011-02-07 22:25:25 +03:00
desc - > istate & = ~ IRQS_AUTODETECT ;
2011-02-03 00:41:14 +03:00
irq_shutdown ( desc ) ;
2005-04-17 02:20:36 +04:00
} else
if ( i < 32 )
2006-06-29 13:24:40 +04:00
mask | = 1 < < i ;
2005-04-17 02:20:36 +04:00
}
2009-11-17 18:46:45 +03:00
raw_spin_unlock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-29 13:24:40 +04:00
return mask ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( probe_irq_on ) ;
/**
* probe_irq_mask - scan a bitmap of interrupt lines
* @ val : mask of interrupts to consider
*
* Scan the interrupt lines and return a bitmap of active
* autodetect interrupts . The interrupt probe logic state
* is then returned to its previous value .
*
* Note : we need to scan all the irq ' s even though we will
* only return autodetect irq numbers - just so that we reset
* them all to a known state .
*/
unsigned int probe_irq_mask ( unsigned long val )
{
2011-02-07 22:25:25 +03:00
unsigned int mask = 0 ;
2008-10-16 16:19:04 +04:00
struct irq_desc * desc ;
2005-04-17 02:20:36 +04:00
int i ;
2008-10-16 16:19:04 +04:00
for_each_irq_desc ( i , desc ) {
2009-11-17 18:46:45 +03:00
raw_spin_lock_irq ( & desc - > lock ) ;
2011-02-07 22:25:25 +03:00
if ( desc - > istate & IRQS_AUTODETECT ) {
2011-02-08 13:39:15 +03:00
if ( i < 16 & & ! ( desc - > istate & IRQS_WAITING ) )
2005-04-17 02:20:36 +04:00
mask | = 1 < < i ;
2011-02-07 22:25:25 +03:00
desc - > istate & = ~ IRQS_AUTODETECT ;
2011-02-03 00:41:14 +03:00
irq_shutdown ( desc ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-17 18:46:45 +03:00
raw_spin_unlock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-29 13:24:37 +04:00
mutex_unlock ( & probing_active ) ;
2005-04-17 02:20:36 +04:00
return mask & val ;
}
EXPORT_SYMBOL ( probe_irq_mask ) ;
/**
* probe_irq_off - end an interrupt autodetect
* @ val : mask of potential interrupts ( unused )
*
* Scans the unused interrupt lines and returns the line which
* appears to have triggered the interrupt . If no interrupt was
* found then zero is returned . If more than one interrupt is
* found then minus the first candidate is returned to indicate
* their is doubt .
*
* The interrupt probe logic state is returned to its previous
* value .
*
* BUGS : When used in a module ( which arguably shouldn ' t happen )
* nothing prevents two IRQ probe callers from overlapping . The
* results of this are non - optimal .
*/
int probe_irq_off ( unsigned long val )
{
2008-10-16 17:33:18 +04:00
int i , irq_found = 0 , nr_of_irqs = 0 ;
2008-10-16 16:19:04 +04:00
struct irq_desc * desc ;
2005-04-17 02:20:36 +04:00
2008-10-16 16:19:04 +04:00
for_each_irq_desc ( i , desc ) {
2009-11-17 18:46:45 +03:00
raw_spin_lock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
2011-02-07 22:25:25 +03:00
if ( desc - > istate & IRQS_AUTODETECT ) {
2011-02-08 13:39:15 +03:00
if ( ! ( desc - > istate & IRQS_WAITING ) ) {
2008-10-16 17:33:18 +04:00
if ( ! nr_of_irqs )
2005-04-17 02:20:36 +04:00
irq_found = i ;
2008-10-16 17:33:18 +04:00
nr_of_irqs + + ;
2005-04-17 02:20:36 +04:00
}
2011-02-07 22:25:25 +03:00
desc - > istate & = ~ IRQS_AUTODETECT ;
2011-02-03 00:41:14 +03:00
irq_shutdown ( desc ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-17 18:46:45 +03:00
raw_spin_unlock_irq ( & desc - > lock ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-29 13:24:37 +04:00
mutex_unlock ( & probing_active ) ;
2005-04-17 02:20:36 +04:00
2008-10-16 17:33:18 +04:00
if ( nr_of_irqs > 1 )
2005-04-17 02:20:36 +04:00
irq_found = - irq_found ;
2006-06-29 13:24:37 +04:00
2005-04-17 02:20:36 +04:00
return irq_found ;
}
EXPORT_SYMBOL ( probe_irq_off ) ;