diff options
Diffstat (limited to 'kernel/irq/resend.c')
| -rw-r--r-- | kernel/irq/resend.c | 47 | 
1 files changed, 30 insertions, 17 deletions
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 0c46e9fe3a89..edec335c0a7a 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -21,8 +21,9 @@  #ifdef CONFIG_HARDIRQS_SW_RESEND -/* Bitmap to handle software resend of interrupts: */ -static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS); +/* hlist_head to handle software resend of interrupts: */ +static HLIST_HEAD(irq_resend_list); +static DEFINE_RAW_SPINLOCK(irq_resend_lock);  /*   * Run software resends of IRQ's @@ -30,18 +31,17 @@ static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);  static void resend_irqs(struct tasklet_struct *unused)  {  	struct irq_desc *desc; -	int irq; - -	while (!bitmap_empty(irqs_resend, nr_irqs)) { -		irq = find_first_bit(irqs_resend, nr_irqs); -		clear_bit(irq, irqs_resend); -		desc = irq_to_desc(irq); -		if (!desc) -			continue; -		local_irq_disable(); + +	raw_spin_lock_irq(&irq_resend_lock); +	while (!hlist_empty(&irq_resend_list)) { +		desc = hlist_entry(irq_resend_list.first, struct irq_desc, +				   resend_node); +		hlist_del_init(&desc->resend_node); +		raw_spin_unlock(&irq_resend_lock);  		desc->handle_irq(desc); -		local_irq_enable(); +		raw_spin_lock(&irq_resend_lock);  	} +	raw_spin_unlock_irq(&irq_resend_lock);  }  /* Tasklet to handle resend: */ @@ -49,8 +49,6 @@ static DECLARE_TASKLET(resend_tasklet, resend_irqs);  static int irq_sw_resend(struct irq_desc *desc)  { -	unsigned int irq = irq_desc_get_irq(desc); -  	/*  	 * Validate whether this interrupt can be safely injected from  	 * non interrupt context @@ -70,16 +68,31 @@ static int irq_sw_resend(struct irq_desc *desc)  		 */  		if (!desc->parent_irq)  			return -EINVAL; -		irq = desc->parent_irq;  	} -	/* Set it pending and activate the softirq: */ -	set_bit(irq, irqs_resend); +	/* Add to resend_list and activate the softirq: */ +	raw_spin_lock(&irq_resend_lock); +	hlist_add_head(&desc->resend_node, &irq_resend_list); +	raw_spin_unlock(&irq_resend_lock);  	tasklet_schedule(&resend_tasklet);  	return 0;  } +void clear_irq_resend(struct irq_desc *desc) +{ +	raw_spin_lock(&irq_resend_lock); +	hlist_del_init(&desc->resend_node); +	raw_spin_unlock(&irq_resend_lock); +} + +void irq_resend_init(struct irq_desc *desc) +{ +	INIT_HLIST_NODE(&desc->resend_node); +}  #else +void clear_irq_resend(struct irq_desc *desc) {} +void irq_resend_init(struct irq_desc *desc) {} +  static int irq_sw_resend(struct irq_desc *desc)  {  	return -EINVAL;  |