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 | ||
