2006-03-25 03:07:36 -08:00
2006-04-10 22:54:04 -07:00
# include <linux/irq.h>
2009-04-27 17:59:53 -07:00
# include <linux/interrupt.h>
# include "internals.h"
2006-03-25 03:07:36 -08:00
2017-06-20 01:37:19 +02:00
/**
* irq_fixup_move_pending - Cleanup irq move pending from a dying CPU
* @ desc : Interrupt descpriptor to clean up
* @ force_clear : If set clear the move pending bit unconditionally .
* If not set , clear it only when the dying CPU is the
* last one in the pending mask .
*
* Returns true if the pending bit was set and the pending mask contains an
* online CPU other than the dying CPU .
*/
bool irq_fixup_move_pending ( struct irq_desc * desc , bool force_clear )
{
struct irq_data * data = irq_desc_get_irq_data ( desc ) ;
if ( ! irqd_is_setaffinity_pending ( data ) )
return false ;
/*
* The outgoing CPU might be the last online target in a pending
* interrupt move . If that ' s the case clear the pending move bit .
*/
if ( cpumask_any_and ( desc - > pending_mask , cpu_online_mask ) > = nr_cpu_ids ) {
irqd_clr_move_pending ( data ) ;
return false ;
}
if ( force_clear )
irqd_clr_move_pending ( data ) ;
return true ;
}
2011-02-04 18:46:16 +01:00
void irq_move_masked_irq ( struct irq_data * idata )
2006-03-25 03:07:36 -08:00
{
2011-02-04 18:46:16 +01:00
struct irq_desc * desc = irq_data_to_desc ( idata ) ;
2015-06-01 16:05:11 +08:00
struct irq_chip * chip = desc - > irq_data . chip ;
2006-03-25 03:07:36 -08:00
2011-02-05 15:20:04 +01:00
if ( likely ( ! irqd_is_setaffinity_pending ( & desc - > irq_data ) ) )
2006-03-25 03:07:36 -08:00
return ;
2015-06-20 12:05:40 +02:00
irqd_clr_move_pending ( & desc - > irq_data ) ;
2006-03-25 03:07:37 -08:00
/*
* Paranoia : cpu - local interrupts shouldn ' t be calling in here anyway .
*/
2015-06-20 12:05:40 +02:00
if ( irqd_is_per_cpu ( & desc - > irq_data ) ) {
2006-03-25 03:07:37 -08:00
WARN_ON ( 1 ) ;
return ;
}
2009-01-10 21:58:08 -08:00
if ( unlikely ( cpumask_empty ( desc - > pending_mask ) ) )
2006-03-25 03:07:36 -08:00
return ;
2010-09-27 12:45:41 +00:00
if ( ! chip - > irq_set_affinity )
2006-03-25 03:07:36 -08:00
return ;
2009-11-17 16:46:45 +01:00
assert_raw_spin_locked ( & desc - > lock ) ;
2006-03-25 03:07:37 -08:00
2006-03-25 03:07:36 -08:00
/*
* If there was a valid mask to work with , please
* do the disable , re - program , enable sequence .
* This is * not * particularly important for level triggered
* but in a edge trigger case , we might be setting rte
2011-03-30 22:57:33 -03:00
* when an active trigger is coming in . This could
2006-03-25 03:07:36 -08:00
* cause some ioapics to mal - function .
* Being paranoid i guess !
2006-10-04 02:16:29 -07:00
*
* For correct operation this depends on the caller
* masking the irqs .
2006-03-25 03:07:36 -08:00
*/
2012-03-30 23:11:34 +08:00
if ( cpumask_any_and ( desc - > pending_mask , cpu_online_mask ) < nr_cpu_ids )
irq_do_set_affinity ( & desc - > irq_data , desc - > pending_mask , false ) ;
2009-04-27 17:59:53 -07:00
2009-01-10 21:58:08 -08:00
cpumask_clear ( desc - > pending_mask ) ;
2006-03-25 03:07:36 -08:00
}
2006-10-04 02:16:29 -07:00
2011-02-04 18:46:16 +01:00
void irq_move_irq ( struct irq_data * idata )
2006-10-04 02:16:29 -07:00
{
2011-01-28 08:47:15 +01:00
bool masked ;
2006-10-04 02:16:29 -07:00
2015-06-01 16:05:11 +08:00
/*
* Get top level irq_data when CONFIG_IRQ_DOMAIN_HIERARCHY is enabled ,
* and it should be optimized away when CONFIG_IRQ_DOMAIN_HIERARCHY is
* disabled . So we avoid an " #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY " here .
*/
idata = irq_desc_get_irq_data ( irq_data_to_desc ( idata ) ) ;
2011-02-04 18:46:16 +01:00
if ( likely ( ! irqd_is_setaffinity_pending ( idata ) ) )
2006-10-04 02:16:29 -07:00
return ;
2011-03-28 14:10:52 +02:00
if ( unlikely ( irqd_irq_disabled ( idata ) ) )
2007-02-23 04:46:20 -07:00
return ;
2006-10-04 02:16:29 -07:00
2011-01-28 08:47:15 +01:00
/*
* Be careful vs . already masked interrupts . If this is a
* threaded interrupt with ONESHOT set , we can end up with an
* interrupt storm .
*/
2011-03-28 14:10:52 +02:00
masked = irqd_irq_masked ( idata ) ;
2011-01-28 08:47:15 +01:00
if ( ! masked )
2011-02-04 18:46:16 +01:00
idata - > chip - > irq_mask ( idata ) ;
irq_move_masked_irq ( idata ) ;
2011-01-28 08:47:15 +01:00
if ( ! masked )
2011-02-04 18:46:16 +01:00
idata - > chip - > irq_unmask ( idata ) ;
}