diff options
Diffstat (limited to 'kernel/irq/chip.c')
| -rw-r--r-- | kernel/irq/chip.c | 55 | 
1 files changed, 43 insertions, 12 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index a3bb14fbe5c..a2b28a2fd7b 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -40,10 +40,9 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip)  	irq_put_desc_unlock(desc, flags);  	/*  	 * For !CONFIG_SPARSE_IRQ make the irq show up in -	 * allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is -	 * already marked, and this call is harmless. +	 * allocated_irqs.  	 */ -	irq_reserve_irq(irq); +	irq_mark_irq(irq);  	return 0;  }  EXPORT_SYMBOL(irq_set_chip); @@ -214,7 +213,7 @@ void irq_enable(struct irq_desc *desc)  }  /** - * irq_disable - Mark interupt disabled + * irq_disable - Mark interrupt disabled   * @desc:	irq descriptor which should be disabled   *   * If the chip does not implement the irq_disable callback, we @@ -281,6 +280,19 @@ void unmask_irq(struct irq_desc *desc)  	}  } +void unmask_threaded_irq(struct irq_desc *desc) +{ +	struct irq_chip *chip = desc->irq_data.chip; + +	if (chip->flags & IRQCHIP_EOI_THREADED) +		chip->irq_eoi(&desc->irq_data); + +	if (chip->irq_unmask) { +		chip->irq_unmask(&desc->irq_data); +		irq_state_clr_masked(desc); +	} +} +  /*   *	handle_nested_irq - Handle a nested irq from a irq thread   *	@irq:	the interrupt number @@ -435,6 +447,27 @@ static inline void preflow_handler(struct irq_desc *desc)  static inline void preflow_handler(struct irq_desc *desc) { }  #endif +static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip) +{ +	if (!(desc->istate & IRQS_ONESHOT)) { +		chip->irq_eoi(&desc->irq_data); +		return; +	} +	/* +	 * We need to unmask in the following cases: +	 * - Oneshot irq which did not wake the thread (caused by a +	 *   spurious interrupt or a primary handler handling it +	 *   completely). +	 */ +	if (!irqd_irq_disabled(&desc->irq_data) && +	    irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) { +		chip->irq_eoi(&desc->irq_data); +		unmask_irq(desc); +	} else if (!(chip->flags & IRQCHIP_EOI_THREADED)) { +		chip->irq_eoi(&desc->irq_data); +	} +} +  /**   *	handle_fasteoi_irq - irq handler for transparent controllers   *	@irq:	the interrupt number @@ -448,6 +481,8 @@ static inline void preflow_handler(struct irq_desc *desc) { }  void  handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)  { +	struct irq_chip *chip = desc->irq_data.chip; +  	raw_spin_lock(&desc->lock);  	if (unlikely(irqd_irq_inprogress(&desc->irq_data))) @@ -473,18 +508,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)  	preflow_handler(desc);  	handle_irq_event(desc); -	if (desc->istate & IRQS_ONESHOT) -		cond_unmask_irq(desc); +	cond_unmask_eoi_irq(desc, chip); -out_eoi: -	desc->irq_data.chip->irq_eoi(&desc->irq_data); -out_unlock:  	raw_spin_unlock(&desc->lock);  	return;  out: -	if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) -		goto out_eoi; -	goto out_unlock; +	if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) +		chip->irq_eoi(&desc->irq_data); +	raw_spin_unlock(&desc->lock);  }  /**  | 
