diff options
Diffstat (limited to 'kernel/irq/chip.c')
-rw-r--r-- | kernel/irq/chip.c | 92 |
1 files changed, 78 insertions, 14 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index c687ba4363f2..ba566c261adc 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -166,11 +166,11 @@ int set_irq_data(unsigned int irq, void *data) | |||
166 | EXPORT_SYMBOL(set_irq_data); | 166 | EXPORT_SYMBOL(set_irq_data); |
167 | 167 | ||
168 | /** | 168 | /** |
169 | * set_irq_data - set irq type data for an irq | 169 | * set_irq_msi - set MSI descriptor data for an irq |
170 | * @irq: Interrupt number | 170 | * @irq: Interrupt number |
171 | * @entry: Pointer to MSI descriptor data | 171 | * @entry: Pointer to MSI descriptor data |
172 | * | 172 | * |
173 | * Set the hardware irq controller data for an irq | 173 | * Set the MSI descriptor entry for an irq |
174 | */ | 174 | */ |
175 | int set_irq_msi(unsigned int irq, struct msi_desc *entry) | 175 | int set_irq_msi(unsigned int irq, struct msi_desc *entry) |
176 | { | 176 | { |
@@ -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 |
@@ -359,7 +426,6 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
359 | 426 | ||
360 | spin_lock(&desc->lock); | 427 | spin_lock(&desc->lock); |
361 | mask_ack_irq(desc, irq); | 428 | mask_ack_irq(desc, irq); |
362 | desc = irq_remap_to_desc(irq, desc); | ||
363 | 429 | ||
364 | if (unlikely(desc->status & IRQ_INPROGRESS)) | 430 | if (unlikely(desc->status & IRQ_INPROGRESS)) |
365 | goto out_unlock; | 431 | goto out_unlock; |
@@ -383,7 +449,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
383 | 449 | ||
384 | spin_lock(&desc->lock); | 450 | spin_lock(&desc->lock); |
385 | desc->status &= ~IRQ_INPROGRESS; | 451 | desc->status &= ~IRQ_INPROGRESS; |
386 | 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) | ||
387 | desc->chip->unmask(irq); | 456 | desc->chip->unmask(irq); |
388 | out_unlock: | 457 | out_unlock: |
389 | spin_unlock(&desc->lock); | 458 | spin_unlock(&desc->lock); |
@@ -438,7 +507,6 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
438 | desc->status &= ~IRQ_INPROGRESS; | 507 | desc->status &= ~IRQ_INPROGRESS; |
439 | out: | 508 | out: |
440 | desc->chip->eoi(irq); | 509 | desc->chip->eoi(irq); |
441 | desc = irq_remap_to_desc(irq, desc); | ||
442 | 510 | ||
443 | spin_unlock(&desc->lock); | 511 | spin_unlock(&desc->lock); |
444 | } | 512 | } |
@@ -475,7 +543,6 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
475 | !desc->action)) { | 543 | !desc->action)) { |
476 | desc->status |= (IRQ_PENDING | IRQ_MASKED); | 544 | desc->status |= (IRQ_PENDING | IRQ_MASKED); |
477 | mask_ack_irq(desc, irq); | 545 | mask_ack_irq(desc, irq); |
478 | desc = irq_remap_to_desc(irq, desc); | ||
479 | goto out_unlock; | 546 | goto out_unlock; |
480 | } | 547 | } |
481 | kstat_incr_irqs_this_cpu(irq, desc); | 548 | kstat_incr_irqs_this_cpu(irq, desc); |
@@ -483,7 +550,6 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) | |||
483 | /* Start handling the irq */ | 550 | /* Start handling the irq */ |
484 | if (desc->chip->ack) | 551 | if (desc->chip->ack) |
485 | desc->chip->ack(irq); | 552 | desc->chip->ack(irq); |
486 | desc = irq_remap_to_desc(irq, desc); | ||
487 | 553 | ||
488 | /* Mark the IRQ currently in progress.*/ | 554 | /* Mark the IRQ currently in progress.*/ |
489 | desc->status |= IRQ_INPROGRESS; | 555 | desc->status |= IRQ_INPROGRESS; |
@@ -524,7 +590,7 @@ out_unlock: | |||
524 | } | 590 | } |
525 | 591 | ||
526 | /** | 592 | /** |
527 | * handle_percpu_IRQ - Per CPU local irq handler | 593 | * handle_percpu_irq - Per CPU local irq handler |
528 | * @irq: the interrupt number | 594 | * @irq: the interrupt number |
529 | * @desc: the interrupt description structure for this irq | 595 | * @desc: the interrupt description structure for this irq |
530 | * | 596 | * |
@@ -544,10 +610,8 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) | |||
544 | if (!noirqdebug) | 610 | if (!noirqdebug) |
545 | note_interrupt(irq, desc, action_ret); | 611 | note_interrupt(irq, desc, action_ret); |
546 | 612 | ||
547 | if (desc->chip->eoi) { | 613 | if (desc->chip->eoi) |
548 | desc->chip->eoi(irq); | 614 | desc->chip->eoi(irq); |
549 | desc = irq_remap_to_desc(irq, desc); | ||
550 | } | ||
551 | } | 615 | } |
552 | 616 | ||
553 | void | 617 | void |
@@ -578,14 +642,13 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
578 | desc->chip = &dummy_irq_chip; | 642 | desc->chip = &dummy_irq_chip; |
579 | } | 643 | } |
580 | 644 | ||
645 | chip_bus_lock(irq, desc); | ||
581 | spin_lock_irqsave(&desc->lock, flags); | 646 | spin_lock_irqsave(&desc->lock, flags); |
582 | 647 | ||
583 | /* Uninstall? */ | 648 | /* Uninstall? */ |
584 | if (handle == handle_bad_irq) { | 649 | if (handle == handle_bad_irq) { |
585 | if (desc->chip != &no_irq_chip) { | 650 | if (desc->chip != &no_irq_chip) |
586 | mask_ack_irq(desc, irq); | 651 | mask_ack_irq(desc, irq); |
587 | desc = irq_remap_to_desc(irq, desc); | ||
588 | } | ||
589 | desc->status |= IRQ_DISABLED; | 652 | desc->status |= IRQ_DISABLED; |
590 | desc->depth = 1; | 653 | desc->depth = 1; |
591 | } | 654 | } |
@@ -599,6 +662,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
599 | desc->chip->startup(irq); | 662 | desc->chip->startup(irq); |
600 | } | 663 | } |
601 | spin_unlock_irqrestore(&desc->lock, flags); | 664 | spin_unlock_irqrestore(&desc->lock, flags); |
665 | chip_bus_sync_unlock(irq, desc); | ||
602 | } | 666 | } |
603 | EXPORT_SYMBOL_GPL(__set_irq_handler); | 667 | EXPORT_SYMBOL_GPL(__set_irq_handler); |
604 | 668 | ||