diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 38 | 
1 files changed, 17 insertions, 21 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 8c548232ba39..4c69326aa773 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -781,7 +781,7 @@ static void wake_threads_waitq(struct irq_desc *desc)  		wake_up(&desc->wait_for_threads);  } -static void irq_thread_dtor(struct task_work *unused) +static void irq_thread_dtor(struct callback_head *unused)  {  	struct task_struct *tsk = current;  	struct irq_desc *desc; @@ -813,7 +813,7 @@ static void irq_thread_dtor(struct task_work *unused)   */  static int irq_thread(void *data)  { -	struct task_work on_exit_work; +	struct callback_head on_exit_work;  	static const struct sched_param param = {  		.sched_priority = MAX_USER_RT_PRIO/2,  	}; @@ -830,7 +830,7 @@ static int irq_thread(void *data)  	sched_setscheduler(current, SCHED_FIFO, ¶m); -	init_task_work(&on_exit_work, irq_thread_dtor, NULL); +	init_task_work(&on_exit_work, irq_thread_dtor);  	task_work_add(current, &on_exit_work, false);  	while (!irq_wait_for_interrupt(action)) { @@ -893,22 +893,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		return -ENOSYS;  	if (!try_module_get(desc->owner))  		return -ENODEV; -	/* -	 * Some drivers like serial.c use request_irq() heavily, -	 * so we have to be careful not to interfere with a -	 * running system. -	 */ -	if (new->flags & IRQF_SAMPLE_RANDOM) { -		/* -		 * This function might sleep, we want to call it first, -		 * outside of the atomic block. -		 * Yes, this might clear the entropy pool if the wrong -		 * driver is attempted to be loaded, without actually -		 * installing a new handler, but is this really a problem, -		 * only the sysadmin is able to do this. -		 */ -		rand_initialize_irq(irq); -	}  	/*  	 * Check whether the interrupt nests into another interrupt @@ -960,6 +944,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  	}  	/* +	 * Drivers are often written to work w/o knowledge about the +	 * underlying irq chip implementation, so a request for a +	 * threaded irq without a primary hard irq context handler +	 * requires the ONESHOT flag to be set. Some irq chips like +	 * MSI based interrupts are per se one shot safe. Check the +	 * chip flags, so we can avoid the unmask dance at the end of +	 * the threaded handler for those. +	 */ +	if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE) +		new->flags &= ~IRQF_ONESHOT; + +	/*  	 * The following block of code has to be executed atomically  	 */  	raw_spin_lock_irqsave(&desc->lock, flags); @@ -1033,7 +1029,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		 */  		new->thread_mask = 1 << ffz(thread_mask); -	} else if (new->handler == irq_default_primary_handler) { +	} else if (new->handler == irq_default_primary_handler && +		   !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {  		/*  		 * The interrupt was requested with handler = NULL, so  		 * we use the default primary handler for it. But it @@ -1354,7 +1351,6 @@ EXPORT_SYMBOL(free_irq);   *	Flags:   *   *	IRQF_SHARED		Interrupt is shared - *	IRQF_SAMPLE_RANDOM	The interrupt can be used for entropy   *	IRQF_TRIGGER_*		Specify active edge(s) or level   *   */  | 
