diff options
Diffstat (limited to 'kernel/irq/chip.c')
-rw-r--r-- | kernel/irq/chip.c | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 13c68e71b726..c1660194d115 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -222,6 +222,34 @@ int set_irq_chip_data(unsigned int irq, void *data) | |||
222 | } | 222 | } |
223 | EXPORT_SYMBOL(set_irq_chip_data); | 223 | EXPORT_SYMBOL(set_irq_chip_data); |
224 | 224 | ||
225 | /** | ||
226 | * set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq | ||
227 | * | ||
228 | * @irq: Interrupt number | ||
229 | * @nest: 0 to clear / 1 to set the IRQ_NESTED_THREAD flag | ||
230 | * | ||
231 | * The IRQ_NESTED_THREAD flag indicates that on | ||
232 | * request_threaded_irq() no separate interrupt thread should be | ||
233 | * created for the irq as the handler are called nested in the | ||
234 | * context of a demultiplexing interrupt handler thread. | ||
235 | */ | ||
236 | void set_irq_nested_thread(unsigned int irq, int nest) | ||
237 | { | ||
238 | struct irq_desc *desc = irq_to_desc(irq); | ||
239 | unsigned long flags; | ||
240 | |||
241 | if (!desc) | ||
242 | return; | ||
243 | |||
244 | spin_lock_irqsave(&desc->lock, flags); | ||
245 | if (nest) | ||
246 | desc->status |= IRQ_NESTED_THREAD; | ||
247 | else | ||
248 | desc->status &= ~IRQ_NESTED_THREAD; | ||
249 | spin_unlock_irqrestore(&desc->lock, flags); | ||
250 | } | ||
251 | EXPORT_SYMBOL_GPL(set_irq_nested_thread); | ||
252 | |||
225 | /* | 253 | /* |
226 | * default enable function | 254 | * default enable function |
227 | */ | 255 | */ |
@@ -299,6 +327,45 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) | |||
299 | } | 327 | } |
300 | } | 328 | } |
301 | 329 | ||
330 | /* | ||
331 | * handle_nested_irq - Handle a nested irq from a irq thread | ||
332 | * @irq: the interrupt number | ||
333 | * | ||
334 | * Handle interrupts which are nested into a threaded interrupt | ||
335 | * handler. The handler function is called inside the calling | ||
336 | * threads context. | ||
337 | */ | ||
338 | void handle_nested_irq(unsigned int irq) | ||
339 | { | ||
340 | struct irq_desc *desc = irq_to_desc(irq); | ||
341 | struct irqaction *action; | ||
342 | irqreturn_t action_ret; | ||
343 | |||
344 | might_sleep(); | ||
345 | |||
346 | spin_lock_irq(&desc->lock); | ||
347 | |||
348 | kstat_incr_irqs_this_cpu(irq, desc); | ||
349 | |||
350 | action = desc->action; | ||
351 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) | ||
352 | goto out_unlock; | ||
353 | |||
354 | desc->status |= IRQ_INPROGRESS; | ||
355 | spin_unlock_irq(&desc->lock); | ||
356 | |||
357 | action_ret = action->thread_fn(action->irq, action->dev_id); | ||
358 | if (!noirqdebug) | ||
359 | note_interrupt(irq, desc, action_ret); | ||
360 | |||
361 | spin_lock_irq(&desc->lock); | ||
362 | desc->status &= ~IRQ_INPROGRESS; | ||
363 | |||
364 | out_unlock: | ||
365 | spin_unlock_irq(&desc->lock); | ||
366 | } | ||
367 | EXPORT_SYMBOL_GPL(handle_nested_irq); | ||
368 | |||
302 | /** | 369 | /** |
303 | * handle_simple_irq - Simple and software-decoded IRQs. | 370 | * handle_simple_irq - Simple and software-decoded IRQs. |
304 | * @irq: the interrupt number | 371 | * @irq: the interrupt number |
@@ -382,7 +449,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
382 | 449 | ||
383 | spin_lock(&desc->lock); | 450 | spin_lock(&desc->lock); |
384 | desc->status &= ~IRQ_INPROGRESS; | 451 | desc->status &= ~IRQ_INPROGRESS; |
385 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | 452 | |
453 | if (unlikely(desc->status & IRQ_ONESHOT)) | ||
454 | desc->status |= IRQ_MASKED; | ||
455 | else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
386 | desc->chip->unmask(irq); | 456 | desc->chip->unmask(irq); |
387 | out_unlock: | 457 | out_unlock: |
388 | spin_unlock(&desc->lock); | 458 | spin_unlock(&desc->lock); |
@@ -572,6 +642,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
572 | desc->chip = &dummy_irq_chip; | 642 | desc->chip = &dummy_irq_chip; |
573 | } | 643 | } |
574 | 644 | ||
645 | chip_bus_lock(irq, desc); | ||
575 | spin_lock_irqsave(&desc->lock, flags); | 646 | spin_lock_irqsave(&desc->lock, flags); |
576 | 647 | ||
577 | /* Uninstall? */ | 648 | /* Uninstall? */ |
@@ -591,6 +662,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
591 | desc->chip->startup(irq); | 662 | desc->chip->startup(irq); |
592 | } | 663 | } |
593 | spin_unlock_irqrestore(&desc->lock, flags); | 664 | spin_unlock_irqrestore(&desc->lock, flags); |
665 | chip_bus_sync_unlock(irq, desc); | ||
594 | } | 666 | } |
595 | EXPORT_SYMBOL_GPL(__set_irq_handler); | 667 | EXPORT_SYMBOL_GPL(__set_irq_handler); |
596 | 668 | ||