diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 46 | 
1 files changed, 31 insertions, 15 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 9b7f68a00e5..bb32326afe8 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -565,8 +565,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, -				chip ? (chip->name ? : "unknown") : "unknown"); +		pr_debug("genirq: No set_type function for IRQ %d (%s)\n", irq, +			 chip ? (chip->name ? : "unknown") : "unknown");  		return 0;  	} @@ -600,7 +600,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,  		ret = 0;  		break;  	default: -		pr_err("setting trigger mode %lu for irq %u failed (%pF)\n", +		pr_err("genirq: Setting trigger mode %lu for irq %u failed (%pF)\n",  		       flags, irq, chip->irq_set_type);  	}  	if (unmask) @@ -837,8 +837,7 @@ void exit_irq_thread(void)  	action = kthread_data(tsk); -	printk(KERN_ERR -	       "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", +	pr_err("genirq: exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",  	       tsk->comm ? tsk->comm : "", tsk->pid, action->irq);  	desc = irq_to_desc(action->irq); @@ -878,7 +877,6 @@ static int  __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  {  	struct irqaction *old, **old_ptr; -	const char *old_name = NULL;  	unsigned long flags, thread_mask = 0;  	int ret, nested, shared = 0;  	cpumask_var_t mask; @@ -972,10 +970,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		 */  		if (!((old->flags & new->flags) & IRQF_SHARED) ||  		    ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || -		    ((old->flags ^ new->flags) & IRQF_ONESHOT)) { -			old_name = old->name; +		    ((old->flags ^ new->flags) & IRQF_ONESHOT))  			goto mismatch; -		}  		/* All handlers must agree on per-cpuness */  		if ((old->flags & IRQF_PERCPU) != @@ -1031,6 +1027,27 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		 * all existing action->thread_mask bits.  		 */  		new->thread_mask = 1 << ffz(thread_mask); + +	} else if (new->handler == irq_default_primary_handler) { +		/* +		 * The interrupt was requested with handler = NULL, so +		 * we use the default primary handler for it. But it +		 * does not have the oneshot flag set. In combination +		 * with level interrupts this is deadly, because the +		 * default primary handler just wakes the thread, then +		 * the irq lines is reenabled, but the device still +		 * has the level irq asserted. Rinse and repeat.... +		 * +		 * While this works for edge type interrupts, we play +		 * it safe and reject unconditionally because we can't +		 * say for sure which type this interrupt really +		 * has. The type flags are unreliable as the +		 * underlying chip implementation can override them. +		 */ +		pr_err("genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n", +		       irq); +		ret = -EINVAL; +		goto out_mask;  	}  	if (!shared) { @@ -1078,7 +1095,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		if (nmsk != omsk)  			/* hope the handler works with current  trigger mode */ -			pr_warning("IRQ %d uses trigger mode %u; requested %u\n", +			pr_warning("genirq: irq %d uses trigger mode %u; requested %u\n",  				   irq, nmsk, omsk);  	} @@ -1115,14 +1132,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  	return 0;  mismatch: -#ifdef CONFIG_DEBUG_SHIRQ  	if (!(new->flags & IRQF_PROBE_SHARED)) { -		printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq); -		if (old_name) -			printk(KERN_ERR "current handler: %s\n", old_name); +		pr_err("genirq: Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n", +		       irq, new->flags, new->name, old->flags, old->name); +#ifdef CONFIG_DEBUG_SHIRQ  		dump_stack(); -	}  #endif +	}  	ret = -EBUSY;  out_mask:  |