diff options
Diffstat (limited to 'kernel/irq')
| -rw-r--r-- | kernel/irq/chip.c | 43 | ||||
| -rw-r--r-- | kernel/irq/generic-chip.c | 6 | ||||
| -rw-r--r-- | kernel/irq/handle.c | 4 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 11 | ||||
| -rw-r--r-- | kernel/irq/irqdesc.c | 2 | ||||
| -rw-r--r-- | kernel/irq/irqdomain.c | 18 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 64 | ||||
| -rw-r--r-- | kernel/irq/msi.c | 17 | ||||
| -rw-r--r-- | kernel/irq/pm.c | 12 | ||||
| -rw-r--r-- | kernel/irq/resend.c | 22 | ||||
| -rw-r--r-- | kernel/irq/spurious.c | 26 | 
11 files changed, 143 insertions, 82 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 27f4332c7f84..6e40a9539763 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -63,7 +63,7 @@ int irq_set_irq_type(unsigned int irq, unsigned int type)  		return -EINVAL;  	type &= IRQ_TYPE_SENSE_MASK; -	ret = __irq_set_trigger(desc, irq, type); +	ret = __irq_set_trigger(desc, type);  	irq_put_desc_busunlock(desc, flags);  	return ret;  } @@ -187,7 +187,7 @@ int irq_startup(struct irq_desc *desc, bool resend)  		irq_enable(desc);  	}  	if (resend) -		check_irq_resend(desc, desc->irq_data.irq); +		check_irq_resend(desc);  	return ret;  } @@ -315,7 +315,7 @@ void handle_nested_irq(unsigned int irq)  	raw_spin_lock_irq(&desc->lock);  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	action = desc->action;  	if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) { @@ -328,7 +328,7 @@ void handle_nested_irq(unsigned int irq)  	action_ret = action->thread_fn(action->irq, action->dev_id);  	if (!noirqdebug) -		note_interrupt(irq, desc, action_ret); +		note_interrupt(desc, action_ret);  	raw_spin_lock_irq(&desc->lock);  	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); @@ -391,7 +391,7 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc)  		goto out_unlock;  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {  		desc->istate |= IRQS_PENDING; @@ -443,7 +443,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)  		goto out_unlock;  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	/*  	 * If its disabled or no action available @@ -515,7 +515,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)  		goto out;  	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	/*  	 * If its disabled or no action available @@ -583,7 +583,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)  		goto out_unlock;  	} -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	/* Start handling the irq */  	desc->irq_data.chip->irq_ack(&desc->irq_data); @@ -646,7 +646,7 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc)  		goto out_eoi;  	} -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	do {  		if (unlikely(!desc->action)) @@ -675,7 +675,7 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)  {  	struct irq_chip *chip = irq_desc_get_chip(desc); -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	if (chip->irq_ack)  		chip->irq_ack(&desc->irq_data); @@ -705,7 +705,7 @@ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)  	void *dev_id = raw_cpu_ptr(action->percpu_dev_id);  	irqreturn_t res; -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	if (chip->irq_ack)  		chip->irq_ack(&desc->irq_data); @@ -985,6 +985,23 @@ int irq_chip_set_affinity_parent(struct irq_data *data,  }  /** + * irq_chip_set_type_parent - Set IRQ type on the parent interrupt + * @data:	Pointer to interrupt specific data + * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h + * + * Conditional, as the underlying parent chip might not implement it. + */ +int irq_chip_set_type_parent(struct irq_data *data, unsigned int type) +{ +	data = data->parent_data; + +	if (data->chip->irq_set_type) +		return data->chip->irq_set_type(data, type); + +	return -ENOSYS; +} + +/**   * irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware   * @data:	Pointer to interrupt specific data   * @@ -997,13 +1014,13 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data)  		if (data->chip && data->chip->irq_retrigger)  			return data->chip->irq_retrigger(data); -	return -ENOSYS; +	return 0;  }  /**   * irq_chip_set_vcpu_affinity_parent - Set vcpu affinity on the parent interrupt   * @data:	Pointer to interrupt specific data - * @dest:	The vcpu affinity information + * @vcpu_info:	The vcpu affinity information   */  int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info)  { diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 15b370daf234..abd286afbd27 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -553,6 +553,9 @@ static int irq_gc_suspend(void)  			if (data)  				ct->chip.irq_suspend(data);  		} + +		if (gc->suspend) +			gc->suspend(gc);  	}  	return 0;  } @@ -564,6 +567,9 @@ static void irq_gc_resume(void)  	list_for_each_entry(gc, &gc_list, list) {  		struct irq_chip_type *ct = gc->chip_types; +		if (gc->resume) +			gc->resume(gc); +  		if (ct->chip.irq_resume) {  			struct irq_data *data = irq_gc_get_irq_data(gc); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 635480270858..b6eeea8a80c5 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -30,7 +30,7 @@  void handle_bad_irq(unsigned int irq, struct irq_desc *desc)  {  	print_irq_desc(irq, desc); -	kstat_incr_irqs_this_cpu(irq, desc); +	kstat_incr_irqs_this_cpu(desc);  	ack_bad_irq(irq);  } @@ -176,7 +176,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)  	add_interrupt_randomness(irq, flags);  	if (!noirqdebug) -		note_interrupt(irq, desc, retval); +		note_interrupt(desc, retval);  	return retval;  } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 61008b8433ab..eee4b385cffb 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -59,10 +59,9 @@ enum {  #include "debug.h"  #include "settings.h" -extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, -		unsigned long flags); -extern void __disable_irq(struct irq_desc *desc, unsigned int irq); -extern void __enable_irq(struct irq_desc *desc, unsigned int irq); +extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags); +extern void __disable_irq(struct irq_desc *desc); +extern void __enable_irq(struct irq_desc *desc);  extern int irq_startup(struct irq_desc *desc, bool resend);  extern void irq_shutdown(struct irq_desc *desc); @@ -86,7 +85,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *act  irqreturn_t handle_irq_event(struct irq_desc *desc);  /* Resending of interrupts :*/ -void check_irq_resend(struct irq_desc *desc, unsigned int irq); +void check_irq_resend(struct irq_desc *desc);  bool irq_wait_for_poll(struct irq_desc *desc);  void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action); @@ -187,7 +186,7 @@ static inline bool irqd_has_set(struct irq_data *d, unsigned int mask)  	return __irqd_to_state(d) & mask;  } -static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc) +static inline void kstat_incr_irqs_this_cpu(struct irq_desc *desc)  {  	__this_cpu_inc(*desc->kstat_irqs);  	__this_cpu_inc(kstat.irqs_sum); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 4afc457613dd..0a2a4b697bcb 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -582,7 +582,7 @@ int irq_set_percpu_devid(unsigned int irq)  void kstat_incr_irq_this_cpu(unsigned int irq)  { -	kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); +	kstat_incr_irqs_this_cpu(irq_to_desc(irq));  }  /** diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8c3577fef78c..79baaf8a7813 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -187,10 +187,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,  EXPORT_SYMBOL_GPL(irq_domain_add_legacy);  /** - * irq_find_host() - Locates a domain for a given device node + * irq_find_matching_host() - Locates a domain for a given device node   * @node: device-tree node of the interrupt controller + * @bus_token: domain-specific data   */ -struct irq_domain *irq_find_host(struct device_node *node) +struct irq_domain *irq_find_matching_host(struct device_node *node, +					  enum irq_domain_bus_token bus_token)  {  	struct irq_domain *h, *found = NULL;  	int rc; @@ -199,13 +201,19 @@ struct irq_domain *irq_find_host(struct device_node *node)  	 * it might potentially be set to match all interrupts in  	 * the absence of a device node. This isn't a problem so far  	 * yet though... +	 * +	 * bus_token == DOMAIN_BUS_ANY matches any domain, any other +	 * values must generate an exact match for the domain to be +	 * selected.  	 */  	mutex_lock(&irq_domain_mutex);  	list_for_each_entry(h, &irq_domain_list, link) {  		if (h->ops->match) -			rc = h->ops->match(h, node); +			rc = h->ops->match(h, node, bus_token);  		else -			rc = (h->of_node != NULL) && (h->of_node == node); +			rc = ((h->of_node != NULL) && (h->of_node == node) && +			      ((bus_token == DOMAIN_BUS_ANY) || +			       (h->bus_token == bus_token)));  		if (rc) {  			found = h; @@ -215,7 +223,7 @@ struct irq_domain *irq_find_host(struct device_node *node)  	mutex_unlock(&irq_domain_mutex);  	return found;  } -EXPORT_SYMBOL_GPL(irq_find_host); +EXPORT_SYMBOL_GPL(irq_find_matching_host);  /**   * irq_set_default_host() - Set a "default" irq domain diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f9744853b656..ad1b064f94fe 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -115,6 +115,14 @@ EXPORT_SYMBOL(synchronize_irq);  #ifdef CONFIG_SMP  cpumask_var_t irq_default_affinity; +static int __irq_can_set_affinity(struct irq_desc *desc) +{ +	if (!desc || !irqd_can_balance(&desc->irq_data) || +	    !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) +		return 0; +	return 1; +} +  /**   *	irq_can_set_affinity - Check if the affinity of a given irq can be set   *	@irq:		Interrupt to check @@ -122,13 +130,7 @@ cpumask_var_t irq_default_affinity;   */  int irq_can_set_affinity(unsigned int irq)  { -	struct irq_desc *desc = irq_to_desc(irq); - -	if (!desc || !irqd_can_balance(&desc->irq_data) || -	    !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) -		return 0; - -	return 1; +	return __irq_can_set_affinity(irq_to_desc(irq));  }  /** @@ -359,14 +361,13 @@ EXPORT_SYMBOL_GPL(irq_set_affinity_notifier);  /*   * Generic version of the affinity autoselector.   */ -static int -setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) +static int setup_affinity(struct irq_desc *desc, struct cpumask *mask)  {  	struct cpumask *set = irq_default_affinity;  	int node = irq_desc_get_node(desc);  	/* Excludes PER_CPU and NO_BALANCE interrupts */ -	if (!irq_can_set_affinity(irq)) +	if (!__irq_can_set_affinity(desc))  		return 0;  	/* @@ -393,10 +394,10 @@ setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask)  	return 0;  }  #else -static inline int -setup_affinity(unsigned int irq, struct irq_desc *d, struct cpumask *mask) +/* Wrapper for ALPHA specific affinity selector magic */ +static inline int setup_affinity(struct irq_desc *d, struct cpumask *mask)  { -	return irq_select_affinity(irq); +	return irq_select_affinity(irq_desc_get_irq(d));  }  #endif @@ -410,20 +411,20 @@ int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask)  	int ret;  	raw_spin_lock_irqsave(&desc->lock, flags); -	ret = setup_affinity(irq, desc, mask); +	ret = setup_affinity(desc, mask);  	raw_spin_unlock_irqrestore(&desc->lock, flags);  	return ret;  }  #else  static inline int -setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) +setup_affinity(struct irq_desc *desc, struct cpumask *mask)  {  	return 0;  }  #endif -void __disable_irq(struct irq_desc *desc, unsigned int irq) +void __disable_irq(struct irq_desc *desc)  {  	if (!desc->depth++)  		irq_disable(desc); @@ -436,7 +437,7 @@ static int __disable_irq_nosync(unsigned int irq)  	if (!desc)  		return -EINVAL; -	__disable_irq(desc, irq); +	__disable_irq(desc);  	irq_put_desc_busunlock(desc, flags);  	return 0;  } @@ -503,12 +504,13 @@ bool disable_hardirq(unsigned int irq)  }  EXPORT_SYMBOL_GPL(disable_hardirq); -void __enable_irq(struct irq_desc *desc, unsigned int irq) +void __enable_irq(struct irq_desc *desc)  {  	switch (desc->depth) {  	case 0:   err_out: -		WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); +		WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", +		     irq_desc_get_irq(desc));  		break;  	case 1: {  		if (desc->istate & IRQS_SUSPENDED) @@ -516,7 +518,7 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq)  		/* Prevent probing on this irq: */  		irq_settings_set_noprobe(desc);  		irq_enable(desc); -		check_irq_resend(desc, irq); +		check_irq_resend(desc);  		/* fall-through */  	}  	default: @@ -546,7 +548,7 @@ void enable_irq(unsigned int irq)  		 KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))  		goto out; -	__enable_irq(desc, irq); +	__enable_irq(desc);  out:  	irq_put_desc_busunlock(desc, flags);  } @@ -637,8 +639,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)  	return canrequest;  } -int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, -		      unsigned long flags) +int __irq_set_trigger(struct irq_desc *desc, unsigned long flags)  {  	struct irq_chip *chip = desc->irq_data.chip;  	int ret, unmask = 0; @@ -648,7 +649,8 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,  		 * IRQF_TRIGGER_* but the PIC does not support multiple  		 * flow-types?  		 */ -		pr_debug("No set_type function for IRQ %d (%s)\n", irq, +		pr_debug("No set_type function for IRQ %d (%s)\n", +			 irq_desc_get_irq(desc),  			 chip ? (chip->name ? : "unknown") : "unknown");  		return 0;  	} @@ -685,7 +687,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,  		break;  	default:  		pr_err("Setting trigger mode %lu for irq %u failed (%pF)\n", -		       flags, irq, chip->irq_set_type); +		       flags, irq_desc_get_irq(desc), chip->irq_set_type);  	}  	if (unmask)  		unmask_irq(desc); @@ -1221,8 +1223,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		/* Setup the type (level, edge polarity) if configured: */  		if (new->flags & IRQF_TRIGGER_MASK) { -			ret = __irq_set_trigger(desc, irq, -					new->flags & IRQF_TRIGGER_MASK); +			ret = __irq_set_trigger(desc, +						new->flags & IRQF_TRIGGER_MASK);  			if (ret)  				goto out_mask; @@ -1253,7 +1255,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		}  		/* Set default affinity mask once everything is setup */ -		setup_affinity(irq, desc, mask); +		setup_affinity(desc, mask);  	} else if (new->flags & IRQF_TRIGGER_MASK) {  		unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK; @@ -1280,7 +1282,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  	 */  	if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {  		desc->istate &= ~IRQS_SPURIOUS_DISABLED; -		__enable_irq(desc, irq); +		__enable_irq(desc);  	}  	raw_spin_unlock_irqrestore(&desc->lock, flags); @@ -1650,7 +1652,7 @@ void enable_percpu_irq(unsigned int irq, unsigned int type)  	if (type != IRQ_TYPE_NONE) {  		int ret; -		ret = __irq_set_trigger(desc, irq, type); +		ret = __irq_set_trigger(desc, type);  		if (ret) {  			WARN(1, "failed to set type for IRQ%d\n", irq); @@ -1875,6 +1877,7 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which,  	irq_put_desc_busunlock(desc, flags);  	return err;  } +EXPORT_SYMBOL_GPL(irq_get_irqchip_state);  /**   *	irq_set_irqchip_state - set the state of a forwarded interrupt. @@ -1920,3 +1923,4 @@ int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which,  	irq_put_desc_busunlock(desc, flags);  	return err;  } +EXPORT_SYMBOL_GPL(irq_set_irqchip_state); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 7bf1f1bbb7fa..7e6512b9dc1f 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -18,6 +18,23 @@  /* Temparory solution for building, will be removed later */  #include <linux/pci.h> +struct msi_desc *alloc_msi_entry(struct device *dev) +{ +	struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); +	if (!desc) +		return NULL; + +	INIT_LIST_HEAD(&desc->list); +	desc->dev = dev; + +	return desc; +} + +void free_msi_entry(struct msi_desc *entry) +{ +	kfree(entry); +} +  void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)  {  	*msg = entry->msg; diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index d22786a6dbde..21c62617a35a 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -68,7 +68,7 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)  		desc->cond_suspend_depth--;  } -static bool suspend_device_irq(struct irq_desc *desc, int irq) +static bool suspend_device_irq(struct irq_desc *desc)  {  	if (!desc->action || desc->no_suspend_depth)  		return false; @@ -85,7 +85,7 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq)  	}  	desc->istate |= IRQS_SUSPENDED; -	__disable_irq(desc, irq); +	__disable_irq(desc);  	/*  	 * Hardware which has no wakeup source configuration facility @@ -126,7 +126,7 @@ void suspend_device_irqs(void)  		if (irq_settings_is_nested_thread(desc))  			continue;  		raw_spin_lock_irqsave(&desc->lock, flags); -		sync = suspend_device_irq(desc, irq); +		sync = suspend_device_irq(desc);  		raw_spin_unlock_irqrestore(&desc->lock, flags);  		if (sync) @@ -135,7 +135,7 @@ void suspend_device_irqs(void)  }  EXPORT_SYMBOL_GPL(suspend_device_irqs); -static void resume_irq(struct irq_desc *desc, int irq) +static void resume_irq(struct irq_desc *desc)  {  	irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); @@ -150,7 +150,7 @@ static void resume_irq(struct irq_desc *desc, int irq)  	desc->depth++;  resume:  	desc->istate &= ~IRQS_SUSPENDED; -	__enable_irq(desc, irq); +	__enable_irq(desc);  }  static void resume_irqs(bool want_early) @@ -169,7 +169,7 @@ static void resume_irqs(bool want_early)  			continue;  		raw_spin_lock_irqsave(&desc->lock, flags); -		resume_irq(desc, irq); +		resume_irq(desc);  		raw_spin_unlock_irqrestore(&desc->lock, flags);  	}  } diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 9065107f083e..dd95f44f99b2 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -53,7 +53,7 @@ static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);   *   * Is called with interrupts disabled and desc->lock held.   */ -void check_irq_resend(struct irq_desc *desc, unsigned int irq) +void check_irq_resend(struct irq_desc *desc)  {  	/*  	 * We do not resend level type interrupts. Level type @@ -74,14 +74,24 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)  		if (!desc->irq_data.chip->irq_retrigger ||  		    !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {  #ifdef CONFIG_HARDIRQS_SW_RESEND +			unsigned int irq = irq_desc_get_irq(desc); +  			/* -			 * If the interrupt has a parent irq and runs -			 * in the thread context of the parent irq, -			 * retrigger the parent. +			 * If the interrupt is running in the thread +			 * context of the parent irq we need to be +			 * careful, because we cannot trigger it +			 * directly.  			 */ -			if (desc->parent_irq && -			    irq_settings_is_nested_thread(desc)) +			if (irq_settings_is_nested_thread(desc)) { +				/* +				 * If the parent_irq is valid, we +				 * retrigger the parent, otherwise we +				 * do nothing. +				 */ +				if (!desc->parent_irq) +					return;  				irq = desc->parent_irq; +			}  			/* Set it pending and activate the softirq: */  			set_bit(irq, irqs_resend);  			tasklet_schedule(&resend_tasklet); diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index e2514b0e439e..32144175458d 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -60,7 +60,7 @@ bool irq_wait_for_poll(struct irq_desc *desc)  /*   * Recovery handler for misrouted interrupts.   */ -static int try_one_irq(int irq, struct irq_desc *desc, bool force) +static int try_one_irq(struct irq_desc *desc, bool force)  {  	irqreturn_t ret = IRQ_NONE;  	struct irqaction *action; @@ -133,7 +133,7 @@ static int misrouted_irq(int irq)  		if (i == irq)	/* Already tried */  			continue; -		if (try_one_irq(i, desc, false)) +		if (try_one_irq(desc, false))  			ok = 1;  	}  out: @@ -164,7 +164,7 @@ static void poll_spurious_irqs(unsigned long dummy)  			continue;  		local_irq_disable(); -		try_one_irq(i, desc, true); +		try_one_irq(desc, true);  		local_irq_enable();  	}  out: @@ -188,10 +188,9 @@ static inline int bad_action_ret(irqreturn_t action_ret)   * (The other 100-of-100,000 interrupts may have been a correctly   *  functioning device sharing an IRQ with the failing one)   */ -static void -__report_bad_irq(unsigned int irq, struct irq_desc *desc, -		 irqreturn_t action_ret) +static void __report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret)  { +	unsigned int irq = irq_desc_get_irq(desc);  	struct irqaction *action;  	unsigned long flags; @@ -224,14 +223,13 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,  	raw_spin_unlock_irqrestore(&desc->lock, flags);  } -static void -report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) +static void report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret)  {  	static int count = 100;  	if (count > 0) {  		count--; -		__report_bad_irq(irq, desc, action_ret); +		__report_bad_irq(desc, action_ret);  	}  } @@ -272,15 +270,16 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc,  #define SPURIOUS_DEFERRED	0x80000000 -void note_interrupt(unsigned int irq, struct irq_desc *desc, -		    irqreturn_t action_ret) +void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret)  { +	unsigned int irq; +  	if (desc->istate & IRQS_POLL_INPROGRESS ||  	    irq_settings_is_polled(desc))  		return;  	if (bad_action_ret(action_ret)) { -		report_bad_irq(irq, desc, action_ret); +		report_bad_irq(desc, action_ret);  		return;  	} @@ -398,6 +397,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,  		desc->last_unhandled = jiffies;  	} +	irq = irq_desc_get_irq(desc);  	if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {  		int ok = misrouted_irq(irq);  		if (action_ret == IRQ_NONE) @@ -413,7 +413,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,  		/*  		 * The interrupt is stuck  		 */ -		__report_bad_irq(irq, desc, action_ret); +		__report_bad_irq(desc, action_ret);  		/*  		 * Now kill the IRQ  		 */  |